
Com o lançamento do novo React 16.6.0, HOOKS (PROPOSAL) apareceu na documentação. Agora eles estão disponíveis no react 17.0.0-alpha e são discutidos no RFC aberto : React Hooks . Vamos ver o que é e por que é necessário sob o corte.
Sim, é RFC e você pode influenciar a implementação final, discutindo com os criadores do reag porque eles escolheram essa ou aquela abordagem.
Vamos dar uma olhada em como é um gancho padrão:
import { useState } from 'react'; function Example() {
Tente pensar nesse código, este é um teaser e, no final do artigo, você já entenderá o que significa. A primeira coisa que você deve saber é que isso não quebra a compatibilidade com versões anteriores e talvez elas sejam adicionadas na versão 16.7 após a coleta de comentários e sugestões na RFC.
Como os rapazes garantem, este não é um plano para eliminar as aulas de um reagente.
Além disso, ganchos não substituem os conceitos atuais da reação, tudo está no lugar de adereços / estado / contexto / refs. Esta é apenas outra maneira de usar seu poder.
Motivação
Os ganchos resolvem, à primeira vista, problemas não conectados que apareceram com o suporte de dezenas de milhares de componentes ao longo de 5 anos no facebook.
O mais difícil é reutilizar a lógica em componentes com estado, a reação não tem como anexar um comportamento reutilizável ao componente (por exemplo, conectá-lo ao repositório). Se você trabalhou com o React, conhece o conceito de HOC (componente de alta ordem) ou renderiza adereços. Esses padrões são bons o suficiente, mas às vezes são usados excessivamente, exigem reestruturação dos componentes para que possam ser usados, o que geralmente torna o código mais complicado. Vale a pena examinar um aplicativo típico de reação e ficará claro o que está em jogo.

Isso é chamado de inferno envolto - inferno envolto .
Uma aplicação de HOCs sozinha é normal nas realidades atuais, eles conectaram o componente à loja / tema / localização / custom hock, acho que todo mundo sabe disso.
Torna-se claro que a reação precisa de outro mecanismo primitivo para separar a lógica.
Usando ganchos, podemos extrair o estado de um componente para que possa ser testado e reutilizado. Os ganchos permitem reutilizar a lógica do estado sem alterar a hierarquia dos componentes. Isso facilita a troca de links entre muitos componentes ou todo o sistema. Além disso, os componentes da classe parecem bastante assustadores, descrevemos os métodos do ciclo de vida de componentDidMount
/ shouldComponentUpdate
/ componentDidUpdate
, o estado do componente, cria métodos para trabalhar com o estado / lado, vincula métodos para a instância do componente e, assim, pode continuar. Normalmente, esses componentes vão além das linhas x, onde x é difícil o suficiente para entender.
Os ganchos permitem fazer o mesmo dividindo a lógica entre componentes em pequenas funções e usando-os dentro dos componentes.
As aulas são difíceis para pessoas e carros
Ao observar as aulas no Facebook, é um grande obstáculo ao aprender o React. Você precisa entender como this
funciona e, como em outras linguagens de programação, você também deve se lembrar sobre os manipuladores de eventos de ligação. Sem sentenças de sintaxe estáveis, o código parece muito detalhado. As pessoas entendem os padrões de adereços / estado e o chamado fluxo de dados de cima para baixo, mas as classes são bastante difíceis de entender.
Especialmente se não se limitando a modelos, há pouco tempo os caras da reação experimentaram o layout dos componentes com o Prepack e obtiveram resultados promissores, mas, mesmo assim, os componentes da classe permitem criar padrões indesejados indesejados que fazem essas otimizações desaparecerem, as classes também não migram muito bem quando As classes de recarga a quente tornam isso não confiável. Primeiro, os caras queriam fornecer uma API que suporta todas as otimizações e funciona bem com uma reinicialização a quente.
Dê uma olhada nos ganchos
Gancho de estado
O código abaixo renderiza um parágrafo e um botão e, se clicarmos no botão, o valor no parágrafo será incrementado.
import { useState } from 'react'; function Example() {
A partir disso, podemos concluir que esse gancho funciona de maneira semelhante com um conceito como state
.
Um método useState
um pouco mais detalhado usa um argumento, esse é o valor padrão e retorna uma tupla na qual existe o valor em si e o método para alterá-lo, ao contrário de setState, setCount não fará mesclagem de valores, mas simplesmente atualize-o. Também podemos usar várias declarações de estado, por exemplo:
function ExampleWithManyStates() {
Assim, criamos vários estados ao mesmo tempo e não precisamos pensar em como decompô-los de alguma forma. Assim, pode-se distinguir que ganchos são funções que permitem "conectar-se" aos chips de componentes de classe, assim como ganchos não funcionam dentro de classes, é importante lembrar.
Gancho de efeito
Frequentemente, nos componentes da classe, criamos funções de efeito colateral, por exemplo, assinamos eventos ou fazemos solicitações de dados, geralmente para isso usamos os métodos componentDidUpdate
/ componentDidUpdate
import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0);
Quando chamamos useEffect
, dizemos à reação para fazer um 'efeito colateral' após atualizar as alterações na árvore DOM. Os efeitos são declarados dentro do componente, portanto, eles têm acesso a props / state. Além disso, podemos criá-los exatamente da mesma maneira que você quiser.
function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); function handleStatusChange(status) { setIsOnline(status.isOnline); }
Imediatamente, vale a pena prestar atenção ao segundo efeito colateral, retornamos a função, fazemos isso para executar algumas ações após a desmontagem do componente, na nova API isso é chamado de efeitos com a limpeza. Outros efeitos podem retornar qualquer coisa.
Regras de gancho
Ganchos são apenas funções javascript, mas requerem apenas duas regras:
- Ganchos devem ser executados no topo da hierarquia de funções (isso significa que você não deve chamar ganchos em condições e loops, caso contrário, a reação não pode garantir a ordem de execução dos ganchos)
- Ganchos de chamada apenas nas funções React ou componentes funcionais ou ganchos de chamada de ganchos personalizados (abaixo).
Para seguir essas regras, os caras da equipe de reação criaram um plug-in de linter que gerará um erro se você chamar ganchos nos componentes da classe ou em loops e condições.
Ganchos personalizados
Ao mesmo tempo, queremos reutilizar a lógica dos componentes com estado, geralmente os padrões HOC ou de adereços de renderização são usados para isso, mas eles criam volume adicional de nosso aplicativo.
Por exemplo, descrevemos a seguinte função:
import { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; }
Perceba esse código, será um gancho personalizado que podemos chamar em vários componentes. Por exemplo, assim:
function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }
mais ou menos
function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); }
De qualquer forma, reutilizamos o estado do componente, cada chamada para a função useFriendStatus
cria um estado isolado. Também é importante notar que o início desta função começa com a palavra use , o que significa que é um gancho. Recomendamos que você siga este formato. Você pode escrever ganchos personalizados para qualquer coisa, animações / assinaturas / temporizadores e muito mais.
Existem mais alguns ganchos.
useContext
useContext
permite que você use o valor de retorno usual em vez de renderProps, o contexto que queremos recuperar nele e ele o retornará para nós, para que possamos nos livrar de todos os HOCs que passaram o contexto para adereços.
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext);
E agora podemos apenas usar o objeto de contexto no valor de retorno.
useCallback
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
Quantas vezes você teve que criar um componente de uma classe apenas para salvar uma referência a um método? Isso não precisa mais ser feito, podemos usar useCallback e nossos componentes não serão redesenhados porque um novo link para o onClick chegou.
useMemo
Retornamos o valor memorizado, o valor memorizado significa que ele é calculado apenas quando um dos argumentos mudou, na segunda vez que a mesma coisa não será calculada.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Sim, aqui você deve duplicar os valores na matriz para que o gancho entenda que eles não foram alterados.
useRef
useRef
retorna um valor .current
, onde o campo .current
será inicializado com o primeiro argumento, o objeto existirá enquanto o componente existir.
O exemplo mais comum ao se concentrar na entrada
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => {
useImperativeMethods
useImperativeMethods
customiza o valor da instância que é passada do pai e usa ref diretamente. Como sempre, os links diretos devem ser evitados e o forwardRef
deve ser usado
function FancyInput(props, ref) { const inputRef = useRef(); useImperativeMethods(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput);
Neste exemplo, o componente que FancyInput
pode chamar fancyInputRef.current.focus()
.
useMutationEffect
useMutationEffect
muito semelhante ao useEffect
exceto que ele é iniciado de forma síncrona no estágio em que a reação altera os valores do DOM antes da atualização dos componentes vizinhos. Esse gancho deve ser usado para executar mutações no DOM.
É melhor preferir useEffect para impedir o bloqueio de alterações visuais.
useLayoutEffect
useLayoutEffect
é semelhante ao useEffect
exceto que é executado de forma síncrona após todas as atualizações do DOM e a nova renderização síncrona. As atualizações planejadas em useLayoutEffect
são aplicadas de forma síncrona antes que o navegador possa desenhar elementos. Você também deve tentar usar o useEffect
padrão para não bloquear alterações visuais.
useReducer
useReducer
é um gancho para criar um redutor que retorna o estado e a capacidade de despachar alterações:
const [state, dispatch] = useReducer(reducer, initialState);
Se você entende como o Redux funciona, entende como o useReducer
funciona. O mesmo exemplo que estava com o contador acima apenas através do useReducer
:
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return initialState; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset'})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); }
UseReducer também recebe 3 argumentos, esta é a action
que deve ser executada quando o redutor é inicializado:
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return {count: action.payload}; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer( reducer, initialState, {type: 'reset', payload: initialCount}, ); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); }
Também podemos criar um contexto nesse redutor e usá-lo através do gancho useContext
usá-lo em todo o aplicativo. Isso permanece para trabalhos de casa.
Resumir
Hooks são uma abordagem bastante poderosa para resolver o inferno do invólucro e resolver vários problemas, mas todos eles podem ser usados com uma definição de transferência de link . Já começam a aparecer coleções de ganchos para uso ou esta coleção . Você pode aprender mais sobre ganchos na documentação .