Você escreveu vários componentes usando
ganchos . Talvez - eles até criaram um pequeno aplicativo. Em geral, você está bastante satisfeito com o resultado. Você está acostumado à API e, no processo, encontrou alguns truques úteis inesperados. Você até criou alguns de
seus próprios ganchos e reduziu seu código para 300 linhas, colocando neles o que era representado anteriormente pela repetição de fragmentos de programa. O que você fez, você mostrou colegas. "Muito bem", disseram eles sobre o seu projeto.

Mas, às vezes, quando você usa o
useEffect
, os componentes dos mecanismos do software não se encaixam muito bem. Parece que você está perdendo alguma coisa. Tudo isso é semelhante a trabalhar com eventos de ciclo de vida de componentes com base em classe ... mas é realmente assim?
Tentando entender o que exatamente não combina com você, você percebe que está fazendo as seguintes perguntas:
- Como jogar
componentDidMount
usando useEffect
? - Como carregar dados dentro do
useEffect
? O que é []
? - As funções precisam ser especificadas como dependências de efeito?
- Por que um programa às vezes acaba em um loop infinito de recarga de dados?
- Por que o estado antigo às vezes é visível dentro dos efeitos ou são encontradas propriedades antigas?
Quando comecei a usar ganchos, essas perguntas também me atormentaram. Mesmo quando eu estava preparando a documentação, não podia dizer que domino perfeitamente algumas das sutilezas. Desde então, tive vários momentos em que, de repente, percebendo algo importante, eu realmente queria exclamar: "Eureka!" Sobre o que percebi nesses momentos, quero lhe contar. O que você aprendeu sobre o
useEffect
agora permitirá que você veja claramente as respostas óbvias às perguntas acima.
Mas, para ver as respostas a essas perguntas, precisamos primeiro dar um passo atrás. O objetivo deste artigo não é fornecer aos leitores instruções passo a passo para trabalhar com o
useEffect
. Ele visa ajudá-lo, por assim
useEffect
"
useEffect
" o
useEffect
. E, francamente, não há muito o que aprender. De fato, na maior parte do tempo, gastamos esquecendo o que sabíamos antes.
Tudo na minha cabeça se uniu somente depois que parei de olhar para o gancho
useEffect
através do prisma dos métodos familiares do ciclo de vida dos componentes baseados em componentes.
"Você deve esquecer o que foi ensinado"
habr.com/ru/company/ruvds/blog/445276/YodaSupõe-se que o leitor deste material esteja familiarizado com a API
useEffect . Este é um artigo bastante longo, que pode ser comparado com um pequeno livro. O fato é que prefiro expressar meus pensamentos dessa maneira. Abaixo, muito brevemente, são dadas respostas para as perguntas que foram discutidas acima. Talvez sejam úteis para aqueles que não têm tempo ou desejam ler todo o material.
Se o formato em que vamos considerar o
useEffect
, com todas as suas explicações e exemplos, não for muito adequado para você, aguarde um pouco - até o momento em que essas explicações aparecerem em inúmeros outros manuais. Aqui está a mesma história que a própria biblioteca do React, que em 2013 era algo completamente novo. Leva algum tempo para que a comunidade de desenvolvimento reconheça o novo modelo mental e apareça o material educacional baseado nesse modelo.
Respostas às perguntas
Aqui estão respostas curtas para as perguntas feitas no início deste material, destinadas a quem não deseja ler todo o texto. Se, ao ler essas respostas, você sentir que realmente não entende o significado do que lê, examine o material. Você encontrará explicações detalhadas no texto. Se você está lendo tudo, pode pular esta seção.
PlayComo reproduzir componentDidMount usando useEffect?
Embora você possa usar a construção
useEffect(fn, [])
para reproduzir a funcionalidade
componentDidMount
, ela não é o equivalente exato de
componentDidMount
. Ou seja, ao contrário de
componentDidMount
, captura propriedades e estado. Portanto, mesmo dentro do retorno de chamada, você verá as propriedades e o estado iniciais. Se você quiser ver a versão mais recente de algo, escreva-a no link
ref
. Mas geralmente há uma maneira mais simples de estruturar o código, portanto, isso é opcional. Lembre-se de que o modelo de efeitos mentais é diferente daquele aplicável ao
componentDidMount
e a outros métodos de ciclo de vida do componente. Portanto, tentar encontrar os equivalentes exatos pode fazer mais mal do que bem. Para trabalhar produtivamente, você precisa, por assim dizer, "pensar em efeitos". A base de seu modelo mental está mais próxima da implementação da sincronização do que de responder a eventos no ciclo de vida dos componentes.
LoadComo carregar corretamente os dados no useEffect? O que é []?
Aqui está um bom guia para carregar dados usando
useEffect
. Tente ler na íntegra! Não é tão grande quanto isso. Os colchetes,
[]
, representando uma matriz vazia, significam que o efeito não usa os valores que participam do fluxo de dados React e, por esse motivo, seu uso único pode ser considerado seguro. Além disso, o uso de uma matriz vazia de dependências é uma fonte comum de erros no caso de um determinado valor ser realmente usado no efeito. Você precisará dominar várias estratégias (principalmente apresentadas na forma de
useReducer
e
useCallback
) que podem ajudar a eliminar a necessidade de uma dependência, em vez de descartá-la de maneira irracional.
Functions As funções precisam ser especificadas como dependências de efeito?
Recomenda-se que as funções que não precisam de propriedades ou de um estado sejam tomadas fora dos componentes e que as funções usadas apenas pelos efeitos sejam colocadas dentro dos efeitos. Se depois disso, seu efeito ainda usar funções que estão no escopo da renderização (incluindo funções das propriedades), envolva-as em
useCallback
onde elas são declaradas e tente usá-las novamente. Por que isso é importante? As funções podem "ver" os valores das propriedades e do estado, para que participem do fluxo de dados.
Aqui estão informações mais detalhadas sobre isso em nossas Perguntas frequentes.
▍ Por que um programa às vezes acaba em um loop infinito de recarga de dados?
Isso pode acontecer quando o carregamento de dados é realizado em um efeito que não possui um segundo argumento representando as dependências. Sem ele, os efeitos são executados após cada operação de renderização - o que significa que definir o estado fará com que esses efeitos sejam recuperados. Um loop infinito também pode ocorrer se um valor que sempre muda for indicado na matriz de dependências. Descubra que tipo de valor é possível removendo dependências uma por vez. No entanto, remover dependências (ou imprudentemente usar
[]
) geralmente é a abordagem errada para resolver um problema. Em vez disso, você deve encontrar a fonte do problema e realmente resolvê-lo. Por exemplo, funções podem causar um problema semelhante. Você pode ajudar a resolvê-lo colocando-os em efeito, movendo-os para fora dos componentes ou
useCallback
em
useCallback
. Para evitar a criação de vários objetos, você pode usar
useMemo
.
▍ Por que às vezes o estado antigo é visível dentro dos efeitos ou são encontradas propriedades antigas?
Os efeitos sempre “veem” as propriedades e o estado da renderização em que são declarados. Isso ajuda a
evitar erros , mas em alguns casos, pode interferir na operação normal do componente. Nesses casos, você pode usar links de
ref
mutável explicitamente para trabalhar com esses valores (você pode ler sobre isso no final do artigo mencionado acima). Se você acha que vê propriedades ou estado a partir da renderização antiga, mas não espera isso, pode ter perdido algumas dependências. Para aprender a vê-los, use
esta regra do linter. Em alguns dias, isso se tornará algo como sua segunda natureza. Além disso, dê uma olhada
nesta resposta em nossas Perguntas frequentes.
Espero que essas respostas às perguntas tenham sido úteis para quem as lê. Agora vamos falar mais sobre
useEffect
.
Cada renderização possui suas próprias propriedades e estado.
Antes de podermos discutir os efeitos, precisamos falar sobre renderização.
Aqui está o componente do 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> ); }
Dê uma olhada na
<p>You clicked {count} times</p>
. O que ela quer dizer? A constante constante de alguma forma "observa" as mudanças no estado e é atualizada automaticamente? Essa conclusão pode ser considerada uma espécie de primeira ideia valiosa de alguém que está estudando o React, mas não é um
modelo mental preciso do que está acontecendo.
No nosso exemplo,
count
é apenas um número. Isso não é algum tipo de "ligação de dados" mágica, não é algum tipo de "objeto observador" ou "proxy", ou qualquer outra coisa. À nossa frente está um bom número antigo, assim:
const count = 42;
Durante a saída do primeiro componente, o valor da
count
obtido de
useState()
é 0. Quando chamamos
setCount(1)
, o React chama o componente novamente. Essa
count
tempo será 1. E assim por diante:
React chama o componente sempre que atualizarmos o estado. Como resultado, cada operação de renderização “vê” seu próprio valor do estado do
counter
, que, dentro da função, é uma constante.
Como resultado, esta linha não executa nenhuma operação especial de ligação de dados:
<p>You clicked {count} times</p>
Ele incorpora apenas um valor numérico no código gerado durante a renderização. Este número é fornecido pelo React. Quando chamamos
setCount
, o React chama o componente novamente com um valor de
count
diferente. O React atualiza o DOM para que o modelo de objeto do documento corresponda à saída de dados mais recente durante a renderização do componente.
A conclusão mais importante que se pode tirar disso é que a
count
é uma constante dentro de qualquer renderização específica e não muda com o tempo. O componente que é chamado repetidamente muda. Cada renderização "vê" seu próprio valor de
count
, que é isolado para cada uma das operações de renderização.
Neste material, você pode encontrar detalhes sobre esse processo.
Cada renderização possui seus próprios manipuladores de eventos.
Tudo ainda está claro. E os manipuladores de eventos?
Dê uma olhada neste exemplo. Aqui, três segundos depois de clicar no botão, uma caixa de mensagem é exibida com informações sobre o valor armazenado na
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> ); }
Suponha que eu execute a seguinte sequência de ações:
- Trarei o valor da
count
para 3 clicando no botão Click me
. - Clique no botão
Show alert
. - Aumente o valor para 5 antes que o tempo limite expire.
Aumentando o valor da contagem depois de clicar no botão Mostrar alertaO que você acha que aparece na caixa de mensagem? Será exibido 5 lá, que corresponde ao valor da
count
no momento em que o timer foi acionado, ou 3 - ou seja, o valor da
count
no momento em que o botão for pressionado?
Agora você encontrará a resposta para esta pergunta, mas se quiser descobrir tudo sozinho -
aqui está uma versão funcional deste exemplo.
Se o que você viu lhe parece incompreensível - aqui está um exemplo mais próximo da realidade. Imagine um aplicativo de bate-papo no qual, no estado, o
ID
destinatário atual da mensagem esteja armazenado e haja um botão
Send
.
Neste material, o que está acontecendo é considerado em detalhes. De fato, a resposta correta para a pergunta do que aparece na caixa de mensagem é 3.
O mecanismo para exibir uma caixa de mensagem "capturou" o estado no momento em que o botão foi clicado.
Existem maneiras de implementar outra versão do comportamento, mas, por enquanto, trataremos do comportamento padrão do sistema. Ao construir modelos mentais de tecnologias, é importante distinguir o "caminho de menor resistência" de todos os tipos de "saídas de emergência".
Como tudo isso funciona?
Já dissemos que o valor da
count
é uma constante para cada chamada específica à nossa função. Eu acho que vale a pena pensar nisso com mais detalhes. O ponto é que nossa função é chamada várias vezes (uma vez para cada operação de renderização), mas com cada uma dessas chamadas, a
count
interna é uma constante. Essa constante é configurada para algum valor específico (representando o estado de uma operação de renderização específica).
Esse comportamento das funções não é algo especial para o React - as funções comuns se comportam de maneira semelhante:
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);
Neste exemplo, a variável externa
someone
reatribuída várias vezes. A mesma coisa pode acontecer em algum lugar dentro do React, o estado atual do componente pode mudar. No entanto, dentro da função
sayHi
, há um
name
constante local associado à
person
de uma chamada específica. Esta constante é local, portanto, seus valores em diferentes chamadas de função são isolados um do outro! Como resultado, após um tempo limite, cada janela de mensagem exibida “lembra” seu próprio valor de
name
.
Isso explica como nosso manipulador de eventos captura o valor da
count
quando um botão é clicado. Se nós, trabalhando com componentes, aplicamos o mesmo princípio, acontece que cada renderização "vê" seu próprio valor de
count
:
Como resultado, cada renderização, de fato, retorna sua própria "versão"
handleAlertClick
. Cada uma dessas versões "lembra" seu próprio valor de
count
:
É por
isso que ,
neste exemplo, os manipuladores de eventos "pertencem" a renderizações específicas e, quando você clica no botão, o componente usa o estado de
count
dessas renderizações.
Dentro de cada renderização específica, as propriedades e o estado sempre permanecem os mesmos. Mas se diferentes operações de renderização usarem suas próprias propriedades e estado, o mesmo acontecerá com qualquer mecanismo que as utilize (incluindo manipuladores de eventos). Eles também "pertencem" a renderizações específicas. Portanto, mesmo funções assíncronas dentro de manipuladores de eventos “verão” os mesmos valores de
count
.
Deve-se notar que, no exemplo acima, eu
handleAlertClick
os valores de
count
específicos diretamente na função
handleAlertClick
. Essa substituição "mental" não nos prejudicará, pois a
count
constante não pode ser alterada dentro de uma renderização específica. Em primeiro lugar, é uma constante e, em segundo lugar, é um número. Podemos dizer com confiança que também se pode pensar em outros significados, como objetos, mas apenas se aceitarmos como regra não fazer alterações (mutações) do estado. Ao mesmo tempo, estamos satisfeitos com a chamada para
setSomething(newObj)
com um novo objeto, em vez de alterar o existente, pois, com essa abordagem, o estado pertencente à renderização anterior permanece intocado.
Cada renderização tem seus próprios efeitos.
Esse material, como você sabe, é dedicado aos efeitos, mas ainda nem falamos sobre eles. Agora vamos consertar isso. Como se vê, trabalhar com efeitos não é particularmente diferente do que já descobrimos.
Considere
um exemplo da documentação, que é muito semelhante ao que já analisamos:
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> ); }
Agora eu tenho uma pergunta para você. Como um efeito lê o valor mais recente da
count
?
Talvez alguma "ligação de dados" seja usada aqui, ou um "objeto observador" que atualize o valor da
count
dentro da função de efeito? Talvez
count
seja uma variável mutável cujo valor React defina dentro de nosso componente, como resultado do qual o efeito sempre vê sua versão mais recente?
Não.
Já sabemos que, na renderização de um componente em particular, a
count
é uma constante. Até os manipuladores de eventos "veem" o valor da
count
da renderização à qual eles "pertencem" devido ao fato de que a
count
é uma constante localizada em um determinado escopo. O mesmo vale para efeitos!
E deve-se notar que essa não é a
count
variáveis
count
que de alguma forma muda dentro do efeito "inalterado". À nossa frente está a função do próprio efeito, que é diferente em cada operação de renderização.
Cada versão "vê" o valor da
count
da renderização à qual "pertence":
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}
, , . , , , . E isso está errado.
, , . — , ,
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
, , , - . , , , . , ,
, , .
Sumário
, . , , - , , , .
