No ReactJS é possível alterar um clico de vida e estados de componentes funcionais, para conseguirmos isso foi criado os Hooks que fazem essa funcionalidade. Na data dessa publicação a versão do React está na 18.3.1.
Nesse primeiro momento irie mostrar o que acredito serem os principais hooks, que são eles: useState, useEffect e useContext. É muito importante saber usar e entender os hooks pois com eles podemos criar componentes mais simples sem um grau de complexidade grande igual como usávamos classes.
useState
Usado para gerenciar estados de componentes. Para usarmos o useState declaramos igual uma desestruturação de matriz. Sendo o segundo parâmetro dentro do array usado para atribuir valor ao estado. E o paramentro dentro do useState pode ser de qualquer tipo desde nulo, a um booleano e esse valor será o valor inicial do estado.
const [age, setAge] = useState(25)
É possivel atribuir uma função ao valor inicial do estado porem essa função não deve receber valor em seu parâmetro e pode retornar qualquer valor. Abaixo criei uma função que conta até 10 e passei ela no parâmetro do useState, dessa forma que coloquei a função como inicializadora ela será executada apenas uma única vez que é no inicio da aplicação.
function countAge() {
const initialAge = [];
for (let i = 0; i < 10; i++) {
initialAge.push({
id: i,
text: 'Age ' + (i + 1),
});
}
return initialAge;
}
const [age, setAge] = useState(countAge);
Se você passar o valor inicial diretamente no estado chamando a função no parâmetro do useState, a função iniciara toda vez que tiver uma renderização. Para fins de performance, isso não é muito ideal, pois dependendo do que sua função executa, ela poderá sobrecarregar a aplicação.
const [age, setAge] = useState(countAge());
Para alterarmos o valor de um estado, setAge. Usamos o nome set como uma convenção e uma boa prática, pois deixa explícito no código que alteramos o estado. O código abaixo altera o valor do estado toda vez que o usuário pressiona o botão Add, passando para o estado o valor do input.
const [age, setAge] = useState(0);
const [text, setText] = useState('');
return (
<>
<input value={text} onChange={(e) => setText(e.target.value)} />
<button
onClick={() => {
setText('');
setAge(text);
}}
>
Add
</button>
{age}
</>
);
É também é possível passar objetos e matrizes no useState, em situação na qual devemos captar os dados de um formulário isso se torna bastante útil. Lembrando que devemos colocar os spreads para não sobrescrever todo o objeto.
const [obj, setObj] = useState({
name: '',
age: ''
})
return (
<>
<input
value={obj.name}
onChange={e => {
setObj({
...obj,
name: e.target.value
});
}}/>
<input
value={obj.age}
onChange={e => {
setObj({
...obj,
age: e.target.value
});
}}/>
{obj.name}
{obj.age}
</>
);
Observação, como o estado é somete para leitura tentar alterar a sua mutação não é correto. O correto é substituir usando o setObj.
obj.age = 25; // Maneira incorreta
setObj({
...obj,
age: 25
}); // Maneira correta, pois o valor anterior esta sendo substituído por 25.
useEffect
Utilizamos bastante o useEffect para fazer uma requisição a algo externo, como por exemplo uma API, manipular o DOM e subscrever eventos. Sua sintaxe é:
useEffect(setup, dependencies?);
O useEffect recebe uma função anônima e uma dependência, que colocamos dentro do colchetes([ ]). A dependência ela funciona da seguinte forma, no exemplo acima coloquei o endpoint da api em um estado chamado url, e passei ela na dependência do useEffect. Então toda vez que meu estado for alterado o useEffect será executado. Quando a aplicação inicia, ela passa para a URL o valor inicial que defini, e, consequentemente, o useEffect executa. Caso deixemos a dependência vazia(com os colchetes vazios), o useEffect será executado apenas uma única vez que é quando a aplicação se inicia, na primeira renderização.
const [url, setUrl] = useState('https://jsonplaceholder.typicode.com/todos');
useEffect(() => {
fetch(url).then((res) => res.json()).then((data) => console.log(data))
},[url]);
Uma situação bastante comum é não colocar os colchetes da dependência assim a cada renderização o useEffect será executado, então tenha atenção. Caso esteja acontecendo de entrar em ciclo de renderização infinitas, verifique suas dependencias pois pode acontecer que seu estado esta sendo alterado constantemente. No código abaixo mostro um exemplo de renderização inifinita
const [value, setValue] = useState(0);
useEffect(() => {
setValue(value + 1);
},[value])
É possível fazer muita coisa com useEffect o que mostrei acima é apenas o básico, para mais aprofundamento recomendo ler a documentação oficial, deixei o link no fim do post.
useContext
O useContext é um componente muito útil por que ele nos da a possibilidade de acessar valores de um determinado contexto sem precisar passar os valores através de props dos componentes. Um exemplo simples é o idioma da aplicação, imagina se em cada componente da aplicação eu precisasse passar via props o idioma desejado, inviável. Graças ao contexto do React podemos compartilhar dados entre componentes sem ter necessidade deles serem parentes. Abaixo deixo a sintaxe do useContext.
const value = useContext(SomeContext)
Para conseguirmos utilizar o contexto, primeiramente vamos criar um.
const Context = createContext();
O contexto ele tem dentro dele um componente que se chama Provider, que irá envolver todos os componentes que precisam acessar o valor que o contexto está compartilhando.
const Context = ({ children }) => {
const valor = { nome: "FrontMaster" };
return (
<Context.Provider value={valor}>
{children}
</Context.Provider>
);
};
Para acessar o contexto criado em outro canto da aplicação, mas que seja dentro do Provider, basta declarar o useContext e passar como contexto criado como argumento
const Componente = () => {
const contexto = useContext(Context);
return <p>Nome: {contexto.nome}</p>;
};
Use o contexto diretamente no App, assim toda aplicação terá acesso.
const App = () => {
return (
<Context>
<Componente/>
</Context>
);
};
Para um exemplo mais claro irei usar a alternação de tema
const TemaContexto = createContext();
Criação do componente que envolve toda a aplicação com o Provider. Ele irá fornecer o valor atual do tema para todos os componentes abaixo dele.
const TemaProvedor = ({ children }) => {
const [tema, setTema] = useState("claro");
const alternarTema = () => {
setTema((temaAtual) => (temaAtual === "claro" ? "escuro" : "claro"));
};
return (
<TemaContexto.Provider value={{ tema, alternarTema }}>
{children}
</TemaContexto.Provider>
);
};
Em qualquer componente filho do Provider podemos utilizar o contexto criado. Abaixo criei o componente que alterna os temas.
const BotaoTema = () => {
const { alternarTema } = useContext(TemaContexto);
return <button onClick={alternarTema}>Alternar Tema</button>;
};
No outro componente iremos exibir o tema.
const ExibirTema = () => {
const { tema } = useContext(TemaContexto);
return <p>Tema atual: {tema}</p>;
};
Portanto na nossa aplicação(App) iremos usar o TemaProvedor para envolver tudo para que assim todos os componentes tenham acesso ao contexto e assim o valor compartilhado.
const App = () => {
return (
<TemaProvedor>
<div>
<h1>Minha Aplicação</h1>
<ExibirTema />
<BotaoTema />
</div>
</TemaProvedor>
);
};
export default App;
Obrigado por ler até aqui, espero ter ajudado.
Leia também: Como fazer uma requisição no REACT usando o AXIOS.