> For the complete documentation index, see [llms.txt](https://shimozurdo.gitbook.io/frontend/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shimozurdo.gitbook.io/frontend/reactjs/avanzado.md).

# Avanzado

## **ImperativeHandle**

#### **¿Qué es `useImperativeHandle` en React?**

El hook **`useImperativeHandle`** es un hook avanzado de React que permite personalizar y exponer ciertos métodos de un componente hijo cuando se usa una referencia (con `React.forwardRef`). Es útil cuando quieres exponer una API personalizada de un componente hijo para que el componente padre pueda interactuar con él de manera controlada.

En lugar de exponer todo el componente, puedes seleccionar y exponer solo algunas funciones específicas, evitando así que el padre tenga acceso a todo el DOM del hijo.

#### **¿Cuándo usar `useImperativeHandle`?**

* Cuando necesites controlar imperativamente algunos métodos del componente hijo desde el componente padre.
* Ejemplo típico: Un componente de entrada personalizado (como un input) donde deseas exponer métodos como `focus()` o `clear()`.

#### **Cómo se usa `useImperativeHandle`**

La estructura básica es la siguiente:

```javascript
useImperativeHandle(ref, () => ({
  método1,
  método2,
}));
```

* **`ref`**: La referencia que se pasará al componente padre usando `React.forwardRef`.
* **Función retornada**: Un objeto que contiene los métodos que quieres exponer al padre.

#### **Ejemplo práctico**

**1. Componente hijo (Input personalizado)**

En este ejemplo, tenemos un componente de entrada (`CustomInput`) que expone un método `focus` usando `useImperativeHandle`.

```jsx
import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// Usamos forwardRef para pasar la referencia del padre al hijo
const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  // Exponemos el método 'focus' usando useImperativeHandle
  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current.focus();
    },
    clear() {
      inputRef.current.value = '';
    }
  }));

  return <input ref={inputRef} placeholder="Escribe algo..." />;
});

export default CustomInput;
```

**2. Componente padre**

En el componente padre, usamos una referencia (`useRef`) para interactuar con los métodos expuestos del componente hijo (`CustomInput`).

```jsx
import React, { useRef } from 'react';
import CustomInput from './CustomInput';

function ParentComponent() {
  const inputRef = useRef();

  const handleFocusClick = () => {
    inputRef.current.focus(); // Llama al método 'focus' del componente hijo
  };

  const handleClearClick = () => {
    inputRef.current.clear(); // Llama al método 'clear' del componente hijo
  };

  return (
    <div>
      <h2>useImperativeHandle Example</h2>
      <CustomInput ref={inputRef} />
      <button onClick={handleFocusClick}>Focus Input</button>
      <button onClick={handleClearClick}>Clear Input</button>
    </div>
  );
}

export default ParentComponent;
```

#### **Explicación del ejemplo:**

1. **`forwardRef`**: Se usa para permitir que el componente `CustomInput` acepte una referencia (`ref`) desde el componente padre.
2. **`useImperativeHandle`**: Permite exponer los métodos `focus` y `clear` del input.
3. **Interacción**: En el componente padre, podemos llamar a `inputRef.current.focus()` o `inputRef.current.clear()` para interactuar directamente con el input.

#### **¿Por qué usar `useImperativeHandle`?**

* **Encapsulamiento**: Ayuda a mantener el encapsulamiento. No expone todo el DOM del hijo, solo los métodos necesarios.
* **Control de acceso**: Puedes controlar cuáles métodos se exponen al componente padre.
* **Uso imperativo**: Proporciona una manera de interactuar imperativamente con componentes funcionales, similar a cómo se haría con métodos de clase.

#### **Buenas prácticas**

* Úsalo solo cuando realmente necesites exponer métodos específicos al componente padre. El desarrollo de componentes React debe ser principalmente declarativo.
* Acompáñalo siempre con `forwardRef` para poder pasar y recibir referencias de padres a hijos.

En resumen, **`useImperativeHandle`** es útil para crear APIs controladas y encapsuladas para componentes React, permitiendo una manipulación imperativa solo en los casos que lo ameritan.

## Race Conditions

#### **¿Qué es una Race Condition (Condición de Carrera) en React?**

Una **Race Condition** o **Condición de Carrera** es un error de programación que ocurre cuando múltiples operaciones asíncronas compiten para modificarse o leerse al mismo tiempo, y el resultado final depende del orden en el que se completen esas operaciones. Esto puede llevar a comportamientos inesperados, inconsistencias de datos o errores en tu aplicación.

En **React**, las race conditions suelen ocurrir en situaciones donde múltiples efectos, peticiones de red o actualizaciones de estado ocurren de manera asíncrona, y el resultado depende del orden de finalización de esas operaciones.

#### **Ejemplo de una Race Condition en React**

Imagina que tienes un componente que hace una solicitud de datos a una API cada vez que cambia el valor de un input:

```jsx
import React, { useState, useEffect } from 'react';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [data, setData] = useState(null);

  useEffect(() => {
    // Realiza una petición de datos basada en el query
    const fetchData = async () => {
      const response = await fetch(`https://api.example.com/search?q=${query}`);
      const result = await response.json();
      setData(result);
    };

    if (query) {
      fetchData();
    }
  }, [query]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Buscar..."
      />
      <div>Resultado: {JSON.stringify(data)}</div>
    </div>
  );
}

export default SearchComponent;
```

**¿Qué puede salir mal?**

Si el usuario escribe rápidamente diferentes valores en el input, múltiples peticiones se envían al servidor, y debido a que estas peticiones son asíncronas, la respuesta de la API puede llegar en un orden diferente al que fueron enviadas. Esto significa que los datos mostrados en la interfaz pueden no corresponder al último input ingresado.

Por ejemplo:

1. El usuario escribe "a" y se realiza una solicitud para `?q=a`.
2. Luego escribe "ab" y se realiza una solicitud para `?q=ab`.
3. Si la solicitud para `?q=a` finaliza después de la solicitud para `?q=ab`, el estado se actualizará con datos incorrectos, mostrando resultados para `?q=a` en lugar de `?q=ab`.

#### **Cómo prevenir Race Conditions en React**

Para evitar condiciones de carrera, podemos utilizar diferentes técnicas:

**1. Cancelación de peticiones asíncronas**

Una forma es utilizar un mecanismo de cancelación, como `AbortController`:

```jsx
import React, { useState, useEffect } from 'react';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [data, setData] = useState(null);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      try {
        const response = await fetch(`https://api.example.com/search?q=${query}`, { signal });
        const result = await response.json();
        setData(result);
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('Request was cancelled');
        }
      }
    };

    if (query) {
      fetchData();
    }

    // Limpiar el efecto para cancelar la solicitud anterior
    return () => controller.abort();
  }, [query]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Buscar..."
      />
      <div>Resultado: {JSON.stringify(data)}</div>
    </div>
  );
}

export default SearchComponent;
```

**Explicación:**

* **AbortController** permite cancelar una solicitud fetch antes de que se complete.
* Al limpiar el efecto (`controller.abort()`), la solicitud anterior se cancela si se realiza una nueva petición, evitando que las respuestas lleguen fuera de orden.

**2. Uso de identificadores únicos para las solicitudes**

Otra forma es generar un identificador único para cada solicitud y verificarlo antes de actualizar el estado:

```jsx
useEffect(() => {
  let isCurrent = true; // Identificador para la solicitud actual

  const fetchData = async () => {
    const response = await fetch(`https://api.example.com/search?q=${query}`);
    const result = await response.json();
    if (isCurrent) {
      setData(result);
    }
  };

  if (query) {
    fetchData();
  }

  // Cambiar el identificador para cancelar la actualización de estado
  return () => {
    isCurrent = false;
  };
}, [query]);
```

**Explicación:**

* `isCurrent` actúa como un identificador para la solicitud activa.
* Si una nueva solicitud comienza, la variable `isCurrent` cambia a `false`, impidiendo que el estado se actualice para solicitudes previas.

#### **Resumen**

* **Race Condition** ocurre cuando múltiples operaciones asíncronas compiten para modificar datos y el resultado final depende del orden de finalización.
* En React, esto puede suceder cuando se actualizan estados basados en operaciones asíncronas, como solicitudes HTTP.
* **Técnicas para evitarlo**:
  * Usar **AbortController** para cancelar solicitudes anteriores.
  * Usar identificadores únicos o banderas (`isCurrent`) para verificar qué solicitud es la actual.

Evitar race conditions es importante para asegurar que tu aplicación React se comporte de forma predecible y que los datos mostrados sean siempre correctos.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://shimozurdo.gitbook.io/frontend/reactjs/avanzado.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
