Has escrito varios componentes usando
ganchos . Quizás, incluso crearon una pequeña aplicación. En general, estás bastante contento con el resultado. Está acostumbrado a la API y en el proceso encontró algunos trucos útiles poco evidentes. Incluso creó algunos de
sus propios ganchos y redujo su código a 300 líneas, colocando en ellas lo que anteriormente estaba representado por fragmentos repetidos del programa. Lo que hiciste, lo mostraste a tus colegas. "Bien hecho", dijeron sobre su proyecto.

Pero a veces, cuando usa
useEffect
, los componentes de los mecanismos del software no encajan muy bien. Te parece que te estás perdiendo algo. Todo esto es similar a trabajar con eventos de ciclo de vida de componentes basados en clases ... pero ¿es realmente así?
Al tratar de comprender qué es exactamente lo que no le conviene, se da cuenta de que está haciendo las siguientes preguntas:
- ¿Cómo jugar
componentDidMount
usando useEffect
? - ¿Cómo cargar datos dentro de
useEffect
? ¿Qué es []
? - ¿Deben especificarse las funciones como dependencias de efectos?
- ¿Por qué un programa a veces termina en un ciclo infinito de recarga de datos?
- ¿Por qué el antiguo estado a veces es visible dentro de los efectos o se encuentran propiedades antiguas?
Cuando comencé a usar ganchos, estas preguntas también me atormentaron. Incluso cuando estaba preparando la documentación, no podía decir que dominara perfectamente algunas de las sutilezas. Desde entonces, he tenido varios momentos cuando, de repente, al darme cuenta de algo importante, realmente quería exclamar: "¡Eureka!" Sobre lo que me di cuenta en estos momentos, quiero contarte. Lo que aprenda sobre
useEffect
ahora le permitirá ver claramente las respuestas obvias a las preguntas anteriores.
Pero para ver las respuestas a estas preguntas, primero debemos dar un paso atrás. El propósito de este artículo no es dar a sus lectores algunas instrucciones paso a paso para trabajar con
useEffect
. Su objetivo es ayudarlo, por así
useEffect
"
useEffect
"
useEffect
. Y, francamente, no hay mucho que aprender. De hecho, pasaremos la mayor parte del tiempo olvidando lo que sabíamos antes.
Todo en mi cabeza se unió solo después de que dejé de mirar el gancho
useEffect
través del prisma de los métodos familiares del ciclo de vida de los componentes basados en componentes.
"Debes olvidar lo que te han enseñado"
habr.com/ru/company/ruvds/blog/445276/YodaSe supone que el lector de este material está algo familiarizado con la API
useEffect . Este es un artículo bastante largo, se puede comparar con un libro pequeño. El hecho es que prefiero expresar mis pensamientos de esta manera. A continuación, muy brevemente, se dan respuestas a las preguntas que se discutieron anteriormente. Quizás sean útiles para aquellos que no tienen el tiempo o el deseo de leer todo el material.
Si el formato en el que vamos a considerar
useEffect
, con todas sus explicaciones y ejemplos, no es muy adecuado para usted, puede esperar un poco, hasta el momento en que estas explicaciones aparezcan en muchos otros manuales. Aquí está la misma historia que con la biblioteca React en sí, que en 2013 fue algo completamente nuevo. A la comunidad de desarrollo le lleva algún tiempo reconocer el nuevo modelo mental y que aparezcan los materiales educativos basados en este modelo.
Respuestas a preguntas
Aquí hay respuestas breves a las preguntas formuladas al comienzo de este material, destinadas a aquellos que no desean leer este texto completo. Si, mientras lee estas respuestas, siente que realmente no comprende el significado de lo que lee, mire el material. Encontrará explicaciones detalladas en el texto. Si va a leer todo, puede omitir esta sección.
▍ ¿Cómo jugar componentDidMount usando useEffect?
Aunque puede usar la
useEffect(fn, [])
para reproducir la funcionalidad
componentDidMount
, no es el equivalente exacto de
componentDidMount
. Es decir, a diferencia de
componentDidMount
, captura propiedades y estado. Por lo tanto, incluso dentro de la devolución de llamada, verá las propiedades y el estado iniciales. Si desea ver la última versión de algo, puede escribirla en el enlace de
ref
. Pero generalmente hay una forma más simple de estructurar el código, por lo que hacer esto es opcional. Recuerde que el modelo de efectos mentales es diferente del aplicable a
componentDidMount
y otros métodos de ciclo de vida de componentes. Por lo tanto, tratar de encontrar los equivalentes exactos puede hacer más daño que bien. Para trabajar productivamente, necesita, por así decirlo, "pensar en los efectos". La base de su modelo mental está más cerca de la implementación de la sincronización que de responder a eventos en el ciclo de vida de los componentes.
▍ ¿Cómo cargar correctamente los datos dentro de useEffect? ¿Qué es []?
Aquí hay una buena guía para cargar datos usando
useEffect
. ¡Intenta leerlo en su totalidad! No es tan grande como eso. Los corchetes,
[]
, que representan una matriz vacía, significan que el efecto no usa los valores que participan en el flujo de datos React, y por esta razón su uso único puede considerarse seguro. Además, el uso de una matriz vacía de dependencias es una fuente común de errores en el caso de que un cierto valor se use realmente en el efecto. Necesitará dominar varias estrategias (presentadas principalmente en forma de
useReducer
y
useCallback
) que pueden ayudar a eliminar la necesidad de una dependencia en lugar de descartar esta dependencia sin razón.
▍ ¿Deben especificarse las funciones como dependencias de efectos?
Se recomienda que las funciones que no necesitan propiedades o un estado se tomen fuera de los componentes, y aquellas funciones que se usan solo por efectos se recomienda colocarlas dentro de los efectos. Si después de eso su efecto todavía usa funciones que están dentro del alcance del render (incluidas las funciones de las propiedades), envuélvalas en
useCallback
donde están declaradas e intente usarlas nuevamente. ¿Por qué es esto importante? Las funciones pueden "ver" los valores de las propiedades y el estado, por lo que participan en el flujo de datos.
Aquí hay información más detallada sobre esto en nuestras preguntas frecuentes.
▍ ¿Por qué un programa a veces termina en un ciclo infinito de recarga de datos?
Esto puede suceder cuando la carga de datos se realiza en un efecto que no tiene un segundo argumento que represente las dependencias. Sin él, los efectos se realizan después de cada operación de renderizado, lo que significa que establecer el estado hará que se recuperen dichos efectos. Un bucle infinito también puede ocurrir si un valor que siempre cambia se indica en la matriz de dependencias. Descubra qué tipo de valor es posible eliminando las dependencias de una en una. Sin embargo, eliminar dependencias (o usar precipitadamente
[]
) suele ser el enfoque incorrecto para resolver un problema. En cambio, debe encontrar la fuente del problema y realmente resolverlo. Por ejemplo, las funciones pueden causar un problema similar. Puede ayudar a resolverlo poniéndolos en efecto, moviéndolos fuera de los componentes o envolviéndolos en
useCallback
. Para evitar crear múltiples objetos, puede usar
useMemo
.
▍ ¿Por qué a veces el antiguo estado es visible dentro de los efectos o se encuentran propiedades antiguas?
Los efectos siempre "ven" las propiedades y el estado del render en el que se declaran. Esto ayuda a
prevenir errores , pero en algunos casos puede interferir con el funcionamiento normal del componente. En tales casos, puede usar enlaces de
ref
mutables explícitamente para trabajar con dichos valores (puede leer sobre esto al final del artículo mencionado anteriormente). Si cree que ve las propiedades o el estado del render anterior, pero no espera esto, es posible que haya perdido algunas dependencias. Para aprender a verlos, use
esta regla de linter. En un par de días, se convertirá en algo así como su segunda naturaleza. Además, eche un vistazo a
esta respuesta en nuestras Preguntas frecuentes.
Espero que estas respuestas a las preguntas hayan sido útiles para quienes las leen. Ahora hablemos más sobre
useEffect
.
Cada render tiene sus propias propiedades y estado.
Antes de que podamos discutir los efectos, necesitamos hablar sobre el renderizado.
Aquí está el componente contador funcional.
function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Observe de cerca la línea
<p>You clicked {count} times</p>
. ¿Qué quiere decir ella? ¿La constante constante de alguna manera "observa" los cambios en el estado y se actualiza automáticamente? Esta conclusión puede considerarse una especie de valiosa primera idea de alguien que está estudiando React, pero no es un
modelo mental preciso de lo que está sucediendo.
En nuestro ejemplo,
count
es solo un número. Este no es un tipo de "enlace de datos" mágico, no es un tipo de "objeto de observación" o "proxy", o cualquier otra cosa. Ante nosotros hay un viejo número bueno, como este:
const count = 42;
Durante la salida del primer componente, el valor de
count
obtenido de
useState()
es 0. Cuando llamamos a
setCount(1)
, React vuelve a llamar al componente. Esta
count
tiempo será 1. Y así sucesivamente:
React llama al componente cada vez que actualizamos el estado. Como resultado, cada operación de representación "ve" su propio valor del estado del
counter
, que, dentro de la función, es una constante.
Como resultado, esta línea no realiza ninguna operación especial de enlace de datos:
<p>You clicked {count} times</p>
Solo incrusta un valor numérico en el código generado durante la representación. Este número es proporcionado por React. Cuando llamamos a
setCount
, React vuelve a llamar al componente con un valor de
count
diferente. React luego actualiza el DOM para que el modelo de objeto del documento coincida con la última salida de datos durante la representación del componente.
La conclusión más importante que se puede extraer de esto es que el
count
es una constante dentro de cualquier render particular y no cambia con el tiempo. El componente que se llama una y otra vez cambia. Cada render "ve" su propio valor de
count
, que está aislado para cada una de las operaciones de renderizado.
En
este material puede encontrar detalles sobre este proceso.
Cada render tiene sus propios controladores de eventos.
Todo aún está claro. ¿Qué pasa con los controladores de eventos?
Echa un vistazo a este ejemplo. Aquí, tres segundos después de hacer clic en el botón, se muestra un cuadro de mensaje con información sobre el valor almacenado en el
count
:
function Counter() { const [count, setCount] = useState(0); function handleAlertClick() { setTimeout(() => { alert('You clicked on: ' + count); }, 3000); } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <button onClick={handleAlertClick}> Show alert </button> </div> ); }
Supongamos que realizo la siguiente secuencia de acciones:
- Llevaré el valor de
count
a 3 haciendo clic en el botón Click me
. - Haga clic en el botón
Show alert
. - Aumente el valor a 5 antes de que expire el tiempo de espera.
Aumentar el valor de conteo después de hacer clic en el botón Mostrar alerta¿Qué crees que aparece en el cuadro de mensaje? ¿Se mostrará 5 allí, que corresponde al valor de
count
en el momento en que se activó el temporizador, o 3, es decir, el valor de
count
en el momento en que se presiona el botón?
Ahora encontrará la respuesta a esta pregunta, pero si desea averiguar todo usted mismo,
aquí hay una versión funcional de este ejemplo.
Si lo que viste te parece incomprensible, aquí hay un ejemplo más cercano a la realidad. Imagine una aplicación de chat en la que, en estado, se almacena la
ID
destinatario actual del mensaje, y hay un botón
Send
. En
este material, lo que está sucediendo se considera en detalle. De hecho, la respuesta correcta a la pregunta de qué aparece en el cuadro de mensaje es 3.
El mecanismo para mostrar un cuadro de mensaje "capturó" el estado en el momento en que se hizo clic en el botón.
Hay formas de implementar otra versión de comportamiento, pero por ahora trataremos con el comportamiento estándar del sistema. Al construir modelos mentales de tecnologías, es importante distinguir el "camino de menor resistencia" de todo tipo de "salidas de emergencia".
¿Cómo funciona todo esto?
Ya hemos dicho que el valor de la
count
es una constante para cada llamada específica a nuestra función. Creo que vale la pena detenerse en esto con más detalle. El punto es que nuestra función se llama muchas veces (una vez para cada operación de renderizado), pero con cada una de estas llamadas,
count
dentro de ella es una constante. Esta constante se establece en algún valor específico (que representa el estado de una operación de renderización particular).
Este comportamiento de las funciones no es algo especial para React: las funciones ordinarias se comportan de manera similar:
function sayHi(person) { const name = person.name; setTimeout(() => { alert('Hello, ' + name); }, 3000); } let someone = {name: 'Dan'}; sayHi(someone); someone = {name: 'Yuzhi'}; sayHi(someone); someone = {name: 'Dominic'}; sayHi(someone);
En
este ejemplo, la variable externa
someone
reasigna varias veces. Lo mismo puede suceder en algún lugar dentro de React, el estado actual del componente puede cambiar. Sin embargo, dentro de la función
sayHi
hay un
name
constante local que está asociado con la
person
de una llamada en particular. Esta constante es local, por lo tanto, sus valores en diferentes llamadas a funciones están aislados entre sí. Como resultado, después de un tiempo de espera, cada ventana de mensaje visualizada "recuerda" su propio valor de
name
.
Esto explica cómo nuestro controlador de eventos captura el valor de
count
cuando se hace clic en un botón. Si, trabajando con componentes, aplicamos el mismo principio, resulta que cada render "ve" su propio valor de
count
:
Como resultado, cada render, de hecho, devuelve su propia "versión"
handleAlertClick
. Cada una de estas versiones "recuerda" su propio valor de
count
:
Es por eso que en
este ejemplo, los controladores de eventos "pertenecen" a renders específicos, y cuando hace clic en el botón, el componente usa el estado de
count
de estos renders.
Dentro de cada render particular, las propiedades y el estado siempre permanecen iguales. Pero si las diferentes operaciones de representación usan sus propias propiedades y estado, lo mismo sucede con cualquier mecanismo que las use (incluidos los controladores de eventos). También "pertenecen" a renders específicos. Por lo tanto, incluso las funciones asincrónicas dentro de los controladores de eventos "verán" los mismos valores de
count
.
Cabe señalar que en el ejemplo anterior,
handleAlertClick
los valores de
count
específicos directamente en la función
handleAlertClick
. Este reemplazo "mental" no nos hará daño, ya que el
count
constante no se puede cambiar dentro de un render particular. En primer lugar, es una constante, y en segundo lugar, es un número. Podemos decir con confianza que también se puede pensar en otros significados, como los objetos, pero solo si aceptamos, por regla general, no realizar cambios (mutaciones) en el estado. Al mismo tiempo, estamos satisfechos con la llamada a
setSomething(newObj)
con un nuevo objeto en lugar de cambiar el existente, ya que con este enfoque el estado que pertenece al render anterior no se ve afectado.
Cada render tiene sus propios efectos.
Este material, como saben, está dedicado a los efectos, pero aún no hemos hablado de ellos. Ahora lo arreglaremos. Como resultado, trabajar con efectos no es particularmente diferente de lo que ya hemos descubierto.
Considere
un ejemplo de la documentación, que es muy similar al que ya hemos analizado:
function Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Ahora tengo una pregunta para ti. ¿Cómo lee un efecto el valor de
count
más reciente?
¿Tal vez aquí se utiliza algún "enlace de datos" o un "objeto observador" que actualiza el valor de
count
dentro de la función de efecto? ¿Quizás
count
es una variable mutable cuyo valor React establece dentro de nuestro componente, como resultado de lo cual el efecto siempre ve su última versión?
No
Ya sabemos que en la representación de un componente en particular, el
count
es una constante. Incluso los controladores de eventos "ven" el valor de
count
del render al que "pertenecen" debido al hecho de que el
count
es una constante ubicada en un determinado ámbito. ¡Lo mismo es cierto para los efectos!
Y debe tenerse en cuenta que este no es el
count
variable
count
que de alguna manera cambia dentro del efecto "sin cambios". Ante nosotros está la función del efecto en sí, que es diferente en cada operación de renderizado.
Cada versión "ve" el valor de
count
del render al que "pertenece":
React , DOM .
, ( ), , , , «» , «».
, , .
, ( ,
). , , , .
, , :
React:
:
- :
<p>You clicked 0 times</p>
. - , , :
() => { document.title = 'You clicked 0 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 0 times' }
.
, . , , - :
:
React:
:
- :
<p>You clicked 1 times</p>
. - , , :
() => { document.title = 'You clicked 1 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 1 times' }
.
…
, , , , «» .
. :
function Counter() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { console.log(`You clicked ${count} times`); }, 3000); }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
, ?
, . , , , . ! , , , , ,
count
.
.
: «, ! ?».
, ,
this.setState
, , . , ,
, , , :
componentDidUpdate() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); }
,
this.state.count
count
, , . , , , 5 , 5 .
, JavaScript-, , ,
, ,
setTimeout
, . , (React
this.state
, ), .
— , , «» , . , , , . , , . , , , , , ,
.
, ( , , - API ) , .
:
function Example(props) { useEffect(() => { setTimeout(() => { console.log(props.counter); }, 1000); });
, «» . ! . , .
, , - , , , , . ,
ref
,
.
, , , , , . , ( ), «» React-. , , . , .
, , , :
function Example() { const [count, setCount] = useState(0); const latestCount = useRef(count); useEffect(() => {
- React . React
this.state
. , ,
latestCount.current
. , . , , , .
?
, . , , «» .
:
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange); }; });
,
props
—
{id: 10}
,
{id: 20}
— . , :
- React
{id: 10}
. - React
{id: 20}
. - React
{id: 20}
.
( , , .)
, «» - , , «» - , . — , , , . .
React
, . , . . . :
- React
{id: 20}
. - .
{id: 20}
. - React
{id: 10}
. - React
{id: 20}
.
, «»
props
,
{id: 10}
, ,
props
{id: 20}
.
, …
— ?: « ( , , - API ) , ».
! « » , . , , :
, , … , «» , -,
{id: 10}
.
React . , , .
props
, .
,
React , .
.
, :
function Greeting({ name }) { return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
,
<Greeting name="Dan" />
, —
<Greeting name="Yuzhi" />
,
<Greeting name="Yuzhi" />
.
Hello, Yuzhi
.
, , . React, . , , .
$.addClass
$.removeClass
jQuery- ( — , «»), , CSS- React ( — , «»).
React DOM , . «» «».
.
useEffect
, React, .
function Greeting({ name }) { useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
useEffect
, , . , - , ! , «», «».
,
A
,
B
, —
C
, ,
C
. (, - ), .
, , , . ( ).
?
React
React DOM. DOM , React DOM, - .
, :
<h1 className="Greeting"> Hello, Dan </h1>
:
<h1 className="Greeting"> Hello, Yuzhi </h1>
React :
const oldProps = {className: 'Greeting', children: 'Hello, Dan'}; const newProps = {className: 'Greeting', children: 'Hello, Yuzhi'};
React ,
children
, DOM. ,
className
. :
domNode.innerText = 'Hello, Yuzhi';
- ? , , .
, , - :
function Greeting({ name }) { const [counter, setCounter] = useState(0); useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} <button onClick={() => setCounter(counter + 1)}> Increment </button> </h1> ); }
counter
.
document.title
name
,
name
.
document.title
counter
, .
React … ?
let oldEffect = () => { document.title = 'Hello, Dan'; }; let newEffect = () => { document.title = 'Hello, Dan'; };
— . React , , . ( .
name
.)
, , (
deps
),
useEffect
:
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
, React: «, , , ,
name
».
, , React :
const oldEffect = () => { document.title = 'Hello, Dan'; }; const oldDeps = ['Dan']; const newEffect = () => { document.title = 'Hello, Dan'; }; const newDeps = ['Dan'];
, , ! - - .
React
React — . , , , ,
useEffect
, , , . ( !)
function SearchResults() { async function fetchData() {
FAQ , . .
« !», — . : , , . , , , — , .
, , . , , , , . , . .
, , .
, React
, , React , .
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
—, , ,
[]
, , , , :
useEffect(() => { document.title = 'Hello, ' + name; }, []);
—. , «» , , .
, , , . , : «
setInterval
clearInterval
».
. , , ,
useEffect
, , ,
[]
. - , ?
function Counter() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <h1>{count}</h1>; }
, ,
.
, « , », . , , ,
setInterval
, . , ?
, — React , , . ,
count
, React , , , . — .
count
0.
setCount(count + 1)
setCount(0 + 1)
. , —
[]
,
setCount(0 + 1)
:
React, , , — .
count
— , ( ):
const count =
. React .
,. , , React , , . —
- .
React , . , , , .
, , , .
count
:
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
. , , — , .
count
,
count
,
setCount(count + 1)
:
,
setInterval
,
count
, . , .
,, , , . — , .
.
,
count
.
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
, ,
count
. ,
count
setCount
. , ,
count
. , ,
setState
:
useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(id); }, []);
« ». ,
count
- ,
setCount(count + 1)
.
count
- ,
count + 1
«» React. React
count
. , React — , , , .
setCount(c => c + 1)
. « React », , . « » , ,
.
, , , . React.
count
:
,.
,
setInterval
, ,
c => c + 1
.
count
. React .
Google Docs
, , — ? , , «», , . , Google Docs . . , .
, . . ,
setCount(c => c + 1)
, ,
setCount(count + 1)
, «»
count
. , ( — «»). « React» —
. .
( ) , Google Docs
. — , React . , , ( , , ) .
,
setCount(c => c + 1)
, . , . , , , , , .
setCount(c => c + 1)
.
useReducer
.
, :
count
step
.
setInterval
,
step
:
function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + step); }, 1000); return () => clearInterval(id); }, [step]); return ( <> <h1>{count}</h1> <input value={step} onChange={e => setStep(Number(e.target.value))} /> </> ); }
.
, React .
step
, . .
:
step
setInterval
—
step
. , , , ! , , , , , .
, , ,
setInterval
,
step
.
step
?
, ,
useReducer
.
,
setSomething(something => ...)
, , . «», , , .
step
dispatch
:
const [state, dispatch] = useReducer(reducer, initialState); const { count, step } = state; useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' });
.
: « , ?». , React ,
dispatch
. .
!
(
dispatch
setstate
useRef
, React , . — .)
, , , , .
step
. , . , . :
const initialState = { count: 0, step: 1, }; function reducer(state, action) { const { count, step } = state; if (action.type === 'tick') { return { count: count + step, step }; } else if (action.type === 'step') { return { count, step: action.step }; } else { throw new Error(); } }
, , , .
useReducer — -
, , , . , , ? , , API
<Counter step={1} />
. ,
props.step
?
, ! , :
function Counter({ step }) { const [count, dispatch] = useReducer(reducer, 0); function reducer(state, action) { if (action.type === 'tick') { return state + step; } else { throw new Error(); } } useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' }); }, 1000); return () => clearInterval(id); }, [dispatch]); return <h1>{count}</h1>; }
, . , , , , .
.
dispatch
. , , . .
, , . «» , , ? ,
dispatch
, React . . .
useReducer
«-» . , . , , , , .
, - , .
, , , :
function SearchResults() { const [data, setData] = useState({ hits: [] }); async function fetchData() { const result = await axios( 'https://hn.algolia.com/api/v1/search?query=react', ); setData(result.data); } useEffect(() => { fetchData(); }, []);
, .
, , . , , , , , , , , .
, , , , :
function SearchResults() {
, , :
function SearchResults() { const [query, setQuery] = useState('react');
, (, ), . .
, . , :
function SearchResults() {
.
? , « ». React, - .
getFetchUrl
,
query
, , , , . — ,
query
:
function SearchResults() { const [query, setQuery] = useState('react'); useEffect(() => { function getFetchUrl() { return 'https://hn.algolia.com/api/v1/search?query=' + query; } async function fetchData() { const result = await axios(getFetchUrl()); setData(result.data); } fetchData(); }, [query]);
.
, « React».
query
. , , , , . , , .
exhaustive-deps
eslint-plugin-react-hooks
, . , , .
.
, ?
. , , . , , .
? , . : React . . , « ». , , . , , , !
, , . ,
getFetchUrl
:
function SearchResults() { function getFetchUrl(query) { return 'https://hn.algolia.com/api/v1/search?query=' + query; } useEffect(() => { const url = getFetchUrl('react');
getFetchUrl
— , .
, «» , .
getFetchUrl
(, , ), :
function SearchResults() {
,
getFetchUrl
. , — . - , , . , , , .
— .
, , :
, . , , .
. ,
useCallback :
function SearchResults() {
useCallback
. : , -, , , .
, . (
'react'
'redux'
). , , ,
query
. , ,
query
,
getFetchUrl
.
,
query
useCallback
:
function SearchResults() { const [query, setQuery] = useState('react'); const getFetchUrl = useCallback(() => {
useCallback
query
, ,
getFetchUrl
,
query
:
function SearchResults() { const [query, setQuery] = useState('react');
useCallback
,
query
,
getFetchUrl
, , .
query
,
getFetchUrl
, . Excel: - , , , .
— , . , :
function Parent() { const [query, setQuery] = useState('react');
fetchData
Parent
query
,
Child
, .
?
, , , , . , , , , :
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, : « , , ,
useEffect
—
componentDidMount
componentDidUpdate
. !».
componentDidUpdate
:
class Child extends Component { state = { data: null }; componentDidMount() { this.props.fetchData(); } componentDidUpdate(prevProps) {
,
fetchData
— ! (, , , .) - , .
this.props.fetchData
prevProps.fetchData
. , , ?
componentDidUpdate(prevProps) { this.props.fetchData(); }
. . ( .) ,
fetchData
this.state.query
?
render() { return <Child fetchData={this.fetchData.bind(this, this.state.query)} />; }
this.props.fetchData !== prevProps.fetchData
true
, ,
query
! .
, , ,
query
Child
. , ,
query
,
query
:
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, , - , , .
, , .
this
, . , , , , - . ,
this.props.fetchData
, , , , , .
-
useCallback
. , , , . , .
useCallback
props.fetchData
.
,
useMemo
:
function ColorPicker() {
,
useCallback
, - . « », , , . , . ,
.
,
fetchData
( ), . , , . («
props.onComplete
, ?») , .
, :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . . — , :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.fetchData(this.props.id); } } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . , . ,
{id: 10}
,
{id: 20}
, , . , , , . .
, , . — , ,
async/await
( , - ) , ( , ).
,
async
-. (, , , , .)
, , ! .
, :
function Article({ id }) { const [article, setArticle] = useState(null); useEffect(() => { let didCancel = false; async function fetchData() { const article = await API.fetchArticle(id); if (!didCancel) { setArticle(article); } } fetchData(); return () => { didCancel = true; }; }, [id]);
, , , . , .
, , , , , . , , , . . — .
useEffect
, , , . React. ,
useEffect
.
, , « », . . , , , , «» , .
,
useEffect
, . — . — , , — , . , , , , API.
, ,
useFetch
, ,
useTheme
, . , ,
useEffect
. , , , .
, ,
useEffect
. — , . , . ?
Suspense React , , - ( : , , ) .
Suspense
, ,
useEffect
, , , - . , , , . , ,
, , .
Resumen
, . , , - , , , .
