Aula 12 – React – Componentes – Classes – Hooks – useEffect
Aula 12 – React – Componentes – Classes – Hooks – useEffect
Voltar para página principal do blog
Todas as aulas desse curso
Aula 11 Aula 13
Meus Canais
Toti:
https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA
Backing track / Play-along:
https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA
Código Fluente
https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w
Putz!
https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Esse é o link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Melhore seu NETWORKING
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no GITHUB.
Ah, se puder, clica na estrela nos meus repositórios pra dá uma força ao meu perfil no GITHUB
Códigos da aula
Usando o hook useEffect()
https://github.com/toticavalcanti/react-hooks-usestate-example/tree/useState-hook-example
Usando classe, componentDidMount() e componentDidUpdate()
https://github.com/toticavalcanti/react-hooks-usestate-example/tree/useEffect-hook-with-class-example
Link da documentação oficial:
https://reactjs.org/tutorial/
Aula 12 – React – Componentes – Classes – Hooks – useEffect
O useEffect() é diferente do useState().
A useState() retorna um par de valores: o state atual e uma função que atualiza o state.
O que o useEffect() faz é obter uma função que é chamada sempre que o componente muda ou sempre que o componente é atualizado e renderizado novamente.
No nosso exemplo, a gente tem no card, um campo para digitar um nome.
Nós vamos fazer o seguinte teste, abri o console do navegador para ver o resultado do console.log(‘Oi’) que tá dentro do useEffect().
Em seguida, vamos digitar qualquer coisa no campo disponível do card.
Vejam que a cada letra nova, vai disparar o useEffect() e imprimir o Oi! do console.log(), porque qualquer mudança no componente que tá na tela, que tá no DOM, vai disparar o useEffect().
Isto é, cada vez que o componente é re-renderizado, ele dispara o useEffect().
useEffect( () => {
console.log('Oi!');
});
Quando o componente for montado pela primeira vez, o useEffect() é disparado, e também, todas as vezes que mudar alguma coisa no componente, como por exemplo, você digitar uma letra a mais no campo do card, ou um backspace.
O useEffect() imita o método de ciclo de vida componentDidMount() e também qualquer um dos métodos de ciclo de vida de atualização, que disparam quando o render() é chamado.
useEffect( () => {
console.log('Oi!');
});
Vamos ao código
O único arquivo que vamos mexer é:
src/components/use-state-component/use-state-example-component.jsx
import React, {useState, useEffect} from 'react';
import Card from '../card/card.component';
const UseEffectExample = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState('Bret');
useEffect(() => {
console.log('Disparou o userEffect()!')
});
return (
<Card>
<input
type='search'
value={searchQuery}
onChange={event => setSearchQuery(event.target.value)}
/>
{user? (
<div>
<h3>{user.name}</h3>
<h3>{user.username}</h3>
<h3>{user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
};
export default UseEffectExample;
Veja o que acontece no console do browser, quando você digita ou deleta qualquer caractere no campo search do card.
E se a gente não quiser disparar o useEffect() a cada update do component?
Queremos que ele se comporte como o componentDidMount().
A forma de fazer isso é passando um segundo parâmetro para ele.
Esse segundo parâmetro será um array.
O que este array recebe são propriedades que esse useEffect() tem acesso e que irão disparar quando o componente for re-renderizado.
Então, se a gente passar [searchQuery] ele vai continuar disparando a cada mudança no campo, como no exemplo mostrado acima.
Se a gente passar [user], o useEffect() só vai disparar na primeira renderização, ou quando o estado do user mudar.
O useEffect() é um listening, isto é, um ouvinte, ele fica ouvindo as propriedades que a gente passa para ele nesse array que é o segundo parâmetro dele.
Então, quando a gente passa o searchQuery no array, ele vai ficar ouvido essa propriedade e sempre que ela mudar, o useEffect() é disparado.
Faça o teste agora passando o array para o userEffect() com o user dentro.
src/components/use-state-component/use-state-example-component.jsx
import React, {useState, useEffect} from 'react';
import Card from '../card/card.component';
const UseEffectExample = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState('Bret');
useEffect(() => {
console.log('Disparou o userEffect()!')
}, [user]);
return (
<Card>
<input
type='search'
value={searchQuery}
onChange={event => setSearchQuery(event.target.value)}
/>
{user? (
<div>
<h3>{user.name}</h3>
<h3>{user.username}</h3>
<h3>{user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
};
export default UseEffectExample;
Veja agora que só disparou quando montou o componente no browser.
O userEffect() é o lugar onde vamos colocar o código assíncrono, isto é, um código que depende de outro sistema, e que leva um tempo para retornar com uma resposta de erro ou de sucesso.
No caso do nosso exemplo, é uma chamada a uma API externa(jsonplaceholder.typicode.com/users).
src/components/use-state-component/use-state-example-component.jsx
import React, {useState, useEffect} from 'react';
import Card from '../card/card.component';
const UseEffectExample = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState('Bret');
useEffect(() => {
console.log('Disparou o userEffect()!')
const fetchData = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users?username=${searchQuery}`);
const resJson = await response.json();
setUser(resJson);
}
fetchData()
});
return (
<Card>
<input
type='search'
value={searchQuery}
onChange={event => setSearchQuery(event.target.value)}
/>
{user? (
<div>
<h3>{user.name}</h3>
<h3>{user.username}</h3>
<h3>{user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
};
export default UseEffectExample;
Veja que a response.json() é assícrona.
Isso é porque após a fetch(), apenas os cabeçalhos foram lidos.
Portanto, para analisar o corpo como JSON, primeiro os dados do corpo devem ser lidos no fluxo de entrada.
E, como a leitura do fluxo TCP é assíncrona, a operação .json() acaba sendo assíncrona.
Observação: a análise real do JSON em si não é assíncrona, só a recuperação dos dados do fluxo de entrada que é assíncrono.
Veja o resultado no browser
Veja que ele vai ficar disparando sem parar, vai ficar em loop.
O padrão do useEffect() é ficar em loop, porque ele é um listening.
O propósito do array que é o segundo parâmetro, é pra dizer para ele ficar ouvindo só algumas propriedades que a gente passar para ele, ou nenhuma como vamos fazer no exemplo abaixo.
Então reforçando, vamos colocar um array vazio como segundo parâmetro do useEffect() para ele não ouvir nenhuma propriedade e daí, não ficar disparando o tempo todo.
src/components/use-state-component/use-state-example-component.jsx
import React, {useState, useEffect} from 'react';
import Card from '../card/card.component';
const UseEffectExample = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState('Bret');
useEffect(() => {
console.log('Disparou o userEffect()!')
const fetchData = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users?username=${searchQuery}`);
const resJson = await response.json();
setUser(resJson);
}
fetchData()
}, []);
return (
<Card>
<input
type='search'
value={searchQuery}
onChange={event => setSearchQuery(event.target.value)}
/>
{user? (
<div>
<h3>{user.name}</h3>
<h3>{user.username}</h3>
<h3>{user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
};
export default UseEffectExample;
Veja o resultado no browser
Como o userEffect() não tá escutando nada, pode mudar qualquer propriedade que ele não vai disparar.
Refatorando para pegar as mudanças da propriedade searchQuery
src/components/use-state-component/use-state-example-component.jsx
import React, {useState, useEffect} from 'react';
import Card from '../card/card.component';
const UseEffectExample = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState('Bret');
useEffect(() => {
'Disparou o userEffect()!'
const fetchData = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users?username=${searchQuery}`);
const resJson = await response.json();
setUser(resJson[0]);
}
fetchData()
}, [searchQuery]);
return (
<Card>
<input
type='search'
value={searchQuery}
onChange={event => setSearchQuery(event.target.value)}
/>
{user? (
<div>
<h3>{user.name}</h3>
<h3>{user.username}</h3>
<h3>{user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
};
export default UseEffectExample;
Veja o resultado no browser
Implementação usando classes ao invés de hooks
src/components/use-state-component/use-state-example-component.jsx
import React from 'react';
import Card from '../card/card.component';
export class StateClassComponent extends React.Component {
constructor() {
super();
this.state = {
user: null,
searchQuery: 'Bret'
};
}
componentDidMount(){
console.log('O componentDidMount() foi disparado')
this.fetchData();
}
componentDidUpdate(previousProps, previousState) {
if (previousState.searchQuery !== this.state.searchQuery) {
console.log('O componentDidUpdatet() foi disparado')
this.fetchData();
}
}
fetchData = async () => {
const resp = await fetch(
`https://jsonplaceholder.typicode.com/users?username=${this.state.searchQuery}`
);
const resJson = await resp.json();
this.setState({ user: resJson[0]});
};
/* handleChange() function to set a new state for input */
handleInputChange = (event) => {
//console.log(event.target.value)
this.setState({
searchQuery: event.target.value
})
}
render() {
return (
<Card>
<input
type='search'
value={this.state.searchQuery}
onChange={(e) => this.handleInputChange(e)}
/>
{this.state.user ? (
<div>
<h3>{this.state.user.name}</h3>
<h3>{this.state.user.username}</h3>
<h3>{this.state.user.email}</h3>
</div>
) : (
<p>Usuário não encontrado</p>
)}
</Card>
);
}
}
export default StateClassComponent;
Veja o resultado no browser
O resultado é exatamente o mesmo.