Referencia de la API de los Hooks
Los Hooks son una nueva incorporación en React 16.8. Te permiten usar estado y otras características de React sin escribir una clase.
Esta página describe las API para los Hooks incorporados en React.
Si los Hooks son nuevos para ti, es posible que desees revisar primero la descripción general. También puedes encontrar información útil en la sección de preguntas frecuentes.
Hooks básicos
useState
const [state, setState] = useState(initialState);
Devuelve un valor con estado y una función para actualizarlo.
Durante el renderizado inicial, el estado devuelto (state
) es el mismo que el valor pasado como primer argumento (initialState
).
La función setState
se usa para actualizar el estado. Acepta un nuevo valor de estado y sitúa en la cola una nueva renderización del componente.
setState(newState);
En las renderizaciones siguientes, el primer valor devuelto por useState
será siempre el estado más reciente después de aplicar las actualizaciones.
Nota
React garantiza que la identidad de la función
setState
es estable y no cambiará en subsecuentes renderizados. Es por eso que es seguro omitirla de la lista de dependencias deuseEffect
ouseCallback
.
Actualizaciones funcionales
Si el nuevo estado se calcula utilizando el estado anterior, puede pasar una función a setState
. La función recibirá el valor anterior y devolverá un valor actualizado. Aquí hay un ejemplo de un componente contador que usa ambas formas de setState
:
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
Los botones ”+” y ”-” usan la forma funcional, porque el valor actualizado se basa en el valor anterior. Pero el botón “Reset” usa la forma normal, porque siempre vuelve a establecer la cuenta al valor inicial.
Si tu función de actualización retorna el mismo valor que el valor del estado actual, el renderizado subsecuente será omitido completamente.
Nota
A diferencia del método
setState
que se encuentra en los componentes de la clase,useState
no combina automáticamente los objetos. Puede replicar este comportamiento combinando la función de actualizador de función con la sintaxis de propagación de objetos:const [state, setState] = useState({}); setState(prevState => { // Object.assign también funcionaría return {...prevState, ...updatedValues}; });
Otra opción es
useReducer
, que es más adecuada para administrar objetos de estado que contienen múltiples subvalores.
Inicialización gradual
El argumento initialState
es el estado utilizado durante el render inicial. En renderizados posteriores, se ignora. Si el estado inicial es el resultado de un cálculo costoso, puede proporcionar una función en su lugar, que se ejecutará solo en el render inicial:
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
Evitar una actualización del estado
Si se actualiza un Hook de estado con el mismo valor que el estado actual, React evitará renderizar los hijos y disparar los efectos. (React utiliza el algoritmo de comparación Object.is
).
Recuerda que React puede necesitar renderizar de nuevo ese componente en específico antes de evitarlo. Esto no debería ser un problema ya que React no irá innecesariamente “más profundo” en el árbol. Si estás realizando cálculos costosos mientras renderizas, puedes optimizarlos con useMemo
.
Batching of state updates
React may group several state updates into a single re-render to improve performance. Normally, this improves performance and shouldn’t affect your application’s behavior.
Before React 18, only updates inside React event handlers were batched. Starting with React 18, batching is enabled for all updates by default. Note that React makes sure that updates from several different user-initiated events — for example, clicking a button twice — are always processed separately and do not get batched. This prevents logical mistakes.
In the rare case that you need to force the DOM update to be applied synchronously, you may wrap it in flushSync
. However, this can hurt performance so do this only where needed.
useEffect
useEffect(didUpdate);
Acepta una función que contiene código imperativo, posiblemente código efectivo.
Las mutaciones, suscripciones, temporizadores, registro y otros efectos secundarios no están permitidos dentro del cuerpo principal de un componente de función (denominado como render phase de React). Si lo hace, dará lugar a errores confusos e inconsistencias en la interfaz de usuario.
En su lugar, use useEffect
. La función pasada a useEffect
se ejecutará después de que el renderizado es confirmado en la pantalla. Piense en los efectos como una escotilla de escape de React del mundo puramente funcional al mundo imperativo.
Por defecto, los efectos se ejecutan después de cada renderizado completado, pero puede elegir ejecutarlo solo cuando ciertos valores han cambiado.
Limpiando un efecto
A menudo, los efectos crean recursos que deben limpiarse antes de que el componente salga de la pantalla, como una suscripción o un ID de temporizador. Para hacer esto, la función pasada a useEffect
puede devolver una función de limpieza. Por ejemplo, para crear una suscripción:
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// Limpiar la suscripción
subscription.unsubscribe();
};
});
La función de limpieza se ejecuta antes de que el componente se elimine de la interfaz de usuario para evitar pérdidas de memoria. Además, si un componente se procesa varias veces (como suele hacer), el efecto anterior se limpia antes de ejecutar el siguiente efecto. En nuestro ejemplo, esto significa que se crea una nueva suscripción en cada actualización. Para evitar disparar un efecto en cada actualización, consulte la siguiente sección.
Tiempo de los efectos
A diferencia de componentDidMount
ycomponentDidUpdate
, la función enviada a useEffect
se inicia después de la disposición y pintada de la página, durante un evento diferido. Esto lo hace adecuado para los muchos efectos secundarios comunes, como la configuración de suscripciones y los controladores de eventos, porque la mayoría de los tipos de trabajo no deben impedir que el navegador actualice la pantalla.
Sin embargo, no todos los efectos pueden ser diferidos. Por ejemplo, una mutación de DOM que es visible para el usuario debe ejecutarse de manera sincrónica antes del siguiente render para que el usuario no perciba una inconsistencia visual. (La distinción es conceptualmente similar a la de los listeners de eventos pasivos y de los activos). Para estos tipos de efectos, React proporciona un Hook adicional llamado useLayoutEffect
. Tiene la misma firma que useEffect
y solo difiere de este último en cuándo se ejecuta.
Adicionalmente, a partir de React 18, la función que se pasa a useEffect
se ejecutará sincrónicamente antes de las etapas de layout y pintura cuando es el resulta de una entrada discreta del usuario como un clic, o cuando el resultado de una actualización envuelta en flushSync
. Este comportamiento permite que el resultado del efecto sea observado por un sistema de eventos o por quien llama a flushSync
.
Nota
Esto solo afecta el tiempo de llamada de la función pasada a
useEffect
- las actualizaciones que se programan dentro de estos efectos aún se difieren. Esto es diferente auseLayoutEffect
, que invoca la función y procesa las actualizaciones dentro de ella inmediatamente.
Aún en los casos en que useEffect
se aplaza hasta después de que el navegador haya pintado, se garantiza que se activará antes de cualquier nuevo render. React siempre eliminará los efectos de un render anterior antes de comenzar una nueva actualización.
Disparar un efecto condicionalmente.
El comportamiento predeterminado para los efectos es ejecutar el efecto después de cada renderizado que se completa. De esa manera, siempre se recrea un efecto si cambia una de sus dependencias.
Sin embargo, esto puede ser excesivo en algunos casos, como el ejemplo de suscripción de la sección anterior. No necesitamos crear una nueva suscripción en cada actualización, solo si las propiedades de source
han cambiado.
Para implementar esto, pase un segundo argumento a useEffect
que es el conjunto de valores de los que depende el efecto. Nuestro ejemplo actualizado se verá así:
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
Ahora la suscripción solo se volverá a crear cuando cambie props.source
.
Nota
Si usas esta optimización, asegúrate de que incluyes todos los valores del ámbito del componente (como props y estado) que cambien a lo largo del tiempo y que sean usados por el efecto. De otra forma, tu código referenciará valores obsoletos de renderizados anteriores. Aprende más cómo tratar con funciones y qué hacer cuando el array cambia con mucha frecuencia.
Si quieres ejecutar un efecto y sanearlo solamente una vez (al montar y desmontar), puedes pasar un array vacío (
[]
) como segundo argumento. Esto le indica a React que el efecto no depende de ningún valor proviniente de las props o el estado, de modo que no necesita volver a ejecutarse. Esto no se gestiona como un caso especial, obedece directamente al modo en el que siempre funcionan los arrays.Si pasas un array vacío (
[]
), las props y el estado dentro del efecto siempre tendrán sus valores iniciales. Si bien pasar[]
como segundo argumento se acerca al conocido modelo mental decomponentDidMount
ycomponentWillUnmount
, a menudo hay mejores soluciones para evitar volver a ejecutar los efectos con demasiada frecuencia. Además, no olvides que React pospone la ejecución deuseEffect
hasta que el navegador finaliza el trazado, de modo que hacer algún trabajo extra no es tan problemático.Recomendamos usar la regla
exhaustive-deps
que forma parte de nuestro paqueteeslint-plugin-react-hooks
. Esta regla advierte cuando las dependencias se especifican incorrectamente y sugiere una solución.
El arreglo de entradas no se pasa como argumentos a la función de efecto. Sin embargo, conceptualmente, eso es lo que representan: cada valor al que se hace referencia dentro de la función de efecto también debería aparecer en el arreglo de entradas. En el futuro, un compilador lo suficientemente avanzado podría crear este arreglo automáticamente.
useContext
const value = useContext(MyContext);
Acepta un objeto de contexto (el valor devuelto de React.createContext
) y devuelve el valor de contexto actual. El valor actual del contexto es determinado por la propiedad value
del <MyContext.Provider>
ascendentemente más cercano en el árbol al componente que hace la llamada.
Cuando el <MyContext.Provider>
ascendentemente más cercano en el árbol se actualiza, el Hook activa una renderización con el value
más reciente del contexto pasado a ese proveedor MyContext
. Incluso sí un ancestro utiliza React.memo
o shouldComponentUpdate
, una nueva renderización aún pasará empezando con el componente en si mismo usando useContext
.
No olvides que el argumento enviado a useContext
debe ser el objeto del contexto en sí mismo:
- Correcto:
useContext(MyContext)
- Incorrecto:
useContext(MyContext.Consumer)
- Incorrecto:
useContext(MyContext.Provider)
Un componente que llama a useContext
siempre se volverá a renderizar cuando el valor del contexto cambie. Si volver a renderizar el componente es costoso, puedes optimizar esto usando memorización.
Consejo
Si estás familiarizado con el API de contexto antes de Hooks,
useContext(MyContext)
es el equivalente astatic contextType = MyContext
en una clase, o a<MyContext.Consumer>
.
useContext(MyContext)
solo te permite leer el contexto y suscribirte a sus cambios. Aún necesitas un<MyContext.Provider>
arriba en el árbol para proveer el valor para este contexto.
Poniendo todo junto con Context.Provider
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> );
}
Este ejemplo está modificado para Hooks a partir del ejemplo anterior en de la guía avanzada de Context, donde puedes encontrar más información sobre cuando y cómo usar Context.
Hooks adicionales
Los siguientes Hooks son variantes de los básicos de la sección anterior o solo son necesarios para casos extremos específicos. No te estreses por aprenderlos por adelantado.
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
Una alternativa a useState
. Acepta un reducer de tipo (state, action) => newState
y devuelve el estado actual emparejado con un método dispatch
. (Si está familiarizado con Redux, ya sabe cómo funciona).
useReducer
a menudo es preferible a useState
cuando se tiene una lógica compleja que involucra múltiples subvalores o cuando el próximo estado depende del anterior. useReducer
además te permite optimizar el rendimiento para componentes que activan actualizaciones profundas, porque puedes pasar hacia abajo dispatch
en lugar de callbacks.
Aquí está el ejemplo del contador de la sección [useState
], reescrito para usar un reductor:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Nota
React garantiza que la identidad de la función
dispatch
es estable y no cambiará en subsecuentes renderizados. Es por eso que es seguro omitirla de la lista de dependencias deuseEffect
ouseCallback
.
Especificar el estado inicial
Hay dos formas diferentes de inicializar el estado de useReducer
. Puedes elegir uno u otro dependiendo de tu caso. La forma más simple para pasar el estado inicial es como un segundo argumento:
const [state, dispatch] = useReducer(
reducer,
{count: initialCount} );
Nota
React no utiliza la convención del argumento
state = initialState
popularizada por Redux. El valor inicial a veces necesita tener una dependencia en las props y por lo tanto tanto se especifica en la llamada al Hook. Si te parece muy importante, puedes llamar auseReducer(reducer, undefined, reducer)
para emular el comportamiento de Redux, pero no se recomienda
Inicialización diferida
También puedes crear el estado inicial de manera diferida. Para hacerlo, le puedes pasar una función init
como tercer argumento. El estado inicial será establecido como init(initialArg)
.
Esto te permite extraer la lógica para calcular el estado inicial fuera del reductor. También es útil para reiniciar el estado luego en respuesta a una acción:
function init(initialCount) { return {count: initialCount};}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset': return init(action.payload); default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init); return (
<>
Count: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset
</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Evitar un dispatch
Si devuelves el mismo valor del estado actual desde un Hook reductor, React evitará renderizar los hijos y disparar efectos. (React utiliza el algoritmo de comparación Object.is
).
Ten en cuenta que React podría aún necesitar renderizar nuevamente ese componente específico antes de evitar el renderizado. Esto no debería ser una preocupación ya que React no va “más adentro” del árbol de forma innecesaria. Si estás haciendo cálculos muy costosos mientras renderizas, puedes optimizarlos con useMemo
.
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Devuelve un callback memorizado.
Pasa un callback en línea y un arreglo de dependencias. useCallback
devolverá una versión memorizada del callback que solo cambia si una de las dependencias ha cambiado. Esto es útil cuando se transfieren callbacks a componentes hijos optimizados que dependen de la igualdad de referencia para evitar renders innecesarias (por ejemplo, shouldComponentUpdate
).
useCallback(fn, deps)
es igual a useMemo(() => fn, deps)
.
Nota
El arreglo de dependencias no se pasa como argumentos al callback. Sin embargo, conceptualmente, eso es lo que representan: cada valor al que se hace referencia dentro del callback también debe aparecer en el arreglo de dependencias. En el futuro, un compilador lo suficientemente avanzado podría crear este arreglo automáticamente.
Recomendamos usar la regla
exhaustive-deps
que forma parte de nuestro paqueteeslint-plugin-react-hooks
. Esta regla advierte cuando las dependencias se especifican incorrectamente y sugiere una solución.
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Devuelve un valor memorizado.
Pasa una función de “crear” y un arreglo de dependencias. useMemo
solo volverá a calcular el valor memorizado cuando una de las dependencias haya cambiado. Esta optimización ayuda a evitar cálculos costosos en cada render.
Recuerde que la función pasada a useMemo
se ejecuta durante el renderizado. No hagas nada allí que normalmente no harías al renderizar. Por ejemplo, los efectos secundarios pertenecen a useEffect
, no auseMemo
.
Si no se proporciona un arreglo, se calculará un nuevo valor en cada renderizado.
Puede confiar en useMemo
como una optimización del rendimiento, no como una garantía semántica. En el futuro, React puede elegir “olvidar” algunos valores previamente memorizados y recalcularlos en el próximo renderizado, por ejemplo para liberar memoria para componentes fuera de pantalla. Escribe tu código para que aún funcione sin useMemo
- y luego agrégalo para optimizar el rendimiento.
Nota
El arreglo de dependencias no se pasa como argumentos a la función. Sin embargo, conceptualmente, eso es lo que representan: cada valor al que se hace referencia dentro de la función también debe aparecer en el arreglo de dependencias. En el futuro, un compilador lo suficientemente avanzado podría crear este arreglo automáticamente.
Recomendamos usar la regla
exhaustive-deps
que forma parte de nuestro paqueteeslint-plugin-react-hooks
. Esta regla advierte cuando las dependencias se especifican incorrectamente y sugiere una solución.
useRef
const refContainer = useRef(initialValue);
useRef
devuelve un objeto ref mutable cuya propiedad .current
se inicializa con el argumento pasado (initialValue
). El objeto devuelto se mantendrá persistente durante la vida completa del componente.
Un caso de uso común es para acceder a un hijo imperativamente:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` apunta al elemento de entrada de texto montado
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
En esencia, useRef
es como una “caja” que puedes mantener en una variable mutable en su propiedad .current
.
Puede que estes familiarizado con las referencias principalmente como un medio para acceder al DOM. Si pasas un objeto de referencia a React con <div ref={myRef} />
, React configurará su propiedad .current
al nodo del DOM correspondiente cuando sea que el nodo cambie.
Sin embargo, useRef()
es útil para más que el atributo ref
. Es conveniente para mantener cualquier valor mutable que es similiar a como usarías campos de instancia en las clases.
Esto funciona debido a que useRef()
crea un objeto JavaScript plano. La única diferencia entre useRef()
y crear un objeto {current: ...}
por ti mismo es que useRef
te dará el mismo objeto de referencia en cada renderizado.
Ten en cuenta que useRef
no notifica cuando su contenido cambia. Mutar la propiedad .current
no causa otro renderizado. Si quieres correr algún código cuando React agregue o quite una referencia de un nodo del DOM, puede que quieras utilizar en su lugar una referencia mediante callback.
useImperativeHandle
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle
personaliza el valor de instancia que se expone a los componentes padres cuando se usaref
. Como siempre, el código imperativo que usa refs debe evitarse en la mayoría de los casos. useImperativeHandle
debe usarse con forwardRef
:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
En este ejemplo, un componente padre que muestra <FancyInput ref={inputRef} />
podría llamar a inputRef.current.focus()
.
useLayoutEffect
La firma es idéntica a useEffect
, pero se dispara de forma síncrona después de todas las mutaciones de DOM. Use esto para leer el diseño del DOM y volver a renderizar de forma sincrónica. Las actualizaciones programadas dentro de useLayoutEffect
se vaciarán sincrónicamente, antes de que el navegador tenga la oportunidad de pintar.
Prefiera el useEffect
estándar cuando sea posible para evitar el bloqueo de actualizaciones visuales.
Consejo
Si estas migrando código de un componente de clase, recuerda que
useLayoutEffect
se activa en la misma fase quecomponentDidMount
ycomponentDidUpdate
. Sin embargo, recomendamos empezar conuseEffect
primero y solo intentar conuseLayoutEffect
si lo anterior causa problemas.Si usas renderizado en el servidor, ten en cuenta que ni
useLayoutEffect
niuseEffect
pueden ejecutarse hasta que no se haya descargado el código JavaScript. Por eso es que React advierte cuando un componente renderizado en el servidor contieneuseLayoutEffect
. Para corregirlo, puedes o bien mover la lógica auseEffect
(si no es necesaria para el primer renderizado), o retrasar el momento de mostrar el componente hasta después de que se haya renderizado el cliente (si el HTML luciera roto, hasta que se ejecuteuseLayoutEffect
).Para excluir del HTML renderizado en el servidor a un componente que necesita efectos de layout, renderízalo condicionalmente con
showChild && <Child />
y retrasa mostrarlo conuseEffect(() => { setShowChild(true); }, [])
. De esta manera, la interfaz de usuario no lucirá rota antes de la hidratación.
useDebugValue
useDebugValue(value)
useDebugValue
puede usarse para mostrar una etiqueta para Hooks personalizados en React DevTools.
Por ejemplo, considera el Hook personalizado useFriendStatus
descrito en “Construyendo sus propios Hooks”:
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// Mostrar una etiqueta en DevTools junto a este Hook // por ejemplo: "FriendStatus: Online" useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
Consejo
No recomendamos agregar valores de depuración a cada Hook personalizado. Es más valioso para los Hooks personalizados que forman parte de bibliotecas compartidas.
Aplazar el formato de los valores de depuración
En algunos casos, formatear un valor para mostrar puede ser una operación costosa. También es innecesario a menos que un Hook sea realmente inspeccionado.
Por esta razón, useDebugValue
acepta una función de formato como un segundo parámetro opcional. Esta función solo se llama si se inspeccionan los Hooks. Recibe el valor de depuración como parámetro y debe devolver un valor de visualización formateado.
Por ejemplo, un Hook personalizado que devolvió un valor de Date
podría evitar llamar a la función toDateString
innecesariamente al pasar el siguiente formateador:
useDebugValue(date, date => date.toDateString());
useDeferredValue
const deferredValue = useDeferredValue(value);
useDeferredValue
accepts a value and returns a new copy of the value that will defer to more urgent updates. If the current render is the result of an urgent update, like user input, React will return the previous value and then render the new value after the urgent render has completed.
This hook is similar to user-space hooks which use debouncing or throttling to defer updates. The benefits to using useDeferredValue
is that React will work on the update as soon as other work finishes (instead of waiting for an arbitrary amount of time), and like startTransition
, deferred values can suspend without triggering an unexpected fallback for existing content.
Memoizing deferred children
useDeferredValue
only defers the value that you pass to it. If you want to prevent a child component from re-rendering during an urgent update, you must also memoize that component with React.memo
or React.useMemo
:
function Typeahead() {
const query = useSearchQuery('');
const deferredQuery = useDeferredValue(query);
// Memoizing tells React to only re-render when deferredQuery changes,
// not when query changes.
const suggestions = useMemo(() =>
<SearchSuggestions query={deferredQuery} />,
[deferredQuery]
);
return (
<>
<SearchInput query={query} />
<Suspense fallback="Loading results...">
{suggestions}
</Suspense>
</>
);
}
Memoizing the children tells React that it only needs to re-render them when deferredQuery
changes and not when query
changes. This caveat is not unique to useDeferredValue
, and it’s the same pattern you would use with similar hooks that use debouncing or throttling.
useTransition
const [isPending, startTransition] = useTransition();
Returns a stateful value for the pending state of the transition, and a function to start it.
startTransition
lets you mark updates in the provided callback as transitions:
startTransition(() => {
setCount(count + 1);
})
isPending
indicates when a transition is active to show a pending state:
function App() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
function handleClick() {
startTransition(() => {
setCount(c => c + 1);
})
}
return (
<div>
{isPending && <Spinner />}
<button onClick={handleClick}>{count}</button>
</div>
);
}
Note:
Updates in a transition yield to more urgent updates such as clicks.
Updates in a transition will not show a fallback for re-suspended content. This allows the user to continue interacting with the current content while rendering the update.
useId
const id = useId();
useId
is a hook for generating unique IDs that are stable across the server and client, while avoiding hydration mismatches.
Note
useId
is not for generating keys in a list. Keys should be generated from your data.
For a basic example, pass the id
directly to the elements that need it:
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>Do you like React?</label>
<input id={id} type="checkbox" name="react"/>
</>
);
};
For multiple IDs in the same component, append a suffix using the same id
:
function NameFields() {
const id = useId();
return (
<div>
<label htmlFor={id + '-firstName'}>First Name</label>
<div>
<input id={id + '-firstName'} type="text" />
</div>
<label htmlFor={id + '-lastName'}>Last Name</label>
<div>
<input id={id + '-lastName'} type="text" />
</div>
</div>
);
}
Note:
useId
generates a string that includes the:
token. This helps ensure that the token is unique, but is not supported in CSS selectors or APIs likequerySelectorAll
.
useId
supports anidentifierPrefix
to prevent collisions in multi-root apps. To configure, see the options forhydrateRoot
andReactDOMServer
.
Library Hooks
The following Hooks are provided for library authors to integrate libraries deeply into the React model, and are not typically used in application code.
useSyncExternalStore
const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
useSyncExternalStore
is a hook recommended for reading and subscribing from external data sources in a way that’s compatible with concurrent rendering features like selective hydration and time slicing.
This method returns the value of the store and accepts three arguments:
subscribe
: function to register a callback that is called whenever the store changes.getSnapshot
: function that returns the current value of the store.getServerSnapshot
: function that returns the snapshot used during server rendering.
The most basic example simply subscribes to the entire store:
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
However, you can also subscribe to a specific field:
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
);
When server rendering, you must serialize the store value used on the server, and provide it to useSyncExternalStore
. React will use this snapshot during hydration to prevent server mismatches:
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
() => INITIAL_SERVER_SNAPSHOT.selectedField,
);
Note:
getSnapshot
must return a cached value. If getSnapshot is called multiple times in a row, it must return the same exact value unless there was a store update in between.A shim is provided for supporting multiple React versions published as
use-sync-external-store/shim
. This shim will preferuseSyncExternalStore
when available, and fallback to a user-space implementation when it’s not.As a convenience, we also provide a version of the API with automatic support for memoizing the result of getSnapshot published as
use-sync-external-store/with-selector
.
useInsertionEffect
useInsertionEffect(didUpdate);
The signature is identical to useEffect
, but it fires synchronously before all DOM mutations. Use this to inject styles into the DOM before reading layout in useLayoutEffect
. Since this hook is limited in scope, this hook does not have access to refs and cannot schedule updates.
Note:
useInsertionEffect
should be limited to css-in-js library authors. PreferuseEffect
oruseLayoutEffect
instead.