A React anunciou oficialmente que o React v16.7.0-alpha (Beta) apresentará Hooks na conferência ReactConf de 2018. O que é Hooks, vamos descobrir.
O que são ganchos?
No processo de desenvolvimento usual, geralmente encontramos os seguintes problemas:
1. É difícil reutilizar e compartilhar a lógica relacionada ao estado
nos componentes 2. Os componentes lógicos complexos são difíceis de desenvolver e manter Quando nossos componentes precisam lidar com vários estados não relacionados, cada função do ciclo de vida pode conter Várias lógicas não relacionadas estão dentro.
3. Devido a mudanças nos negócios, os componentes de função precisam ser alterados para componentes de classe e assim por diante.
O texto acima é mais abstrato: a seguir, usaremos o teclado da API como um exemplo para ilustrar o problema.
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isShowKeyboard: false
}
}
static getDerivedStateFromProps() {
this.keyboardDidShowListener = Keyboard.addListener(
"keyboardDidShow",
this.keyboardDidShowHandler
);
}
keyboardDidShowHandler () {
this.setState({
isShowKeyboard: true
});
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
}
render() {
return (
<View style={styles.container}>
<Text>
当前键盘状态: {this.state.isShowKeyboard}
</Text>
</View>
);
}
}
O caso de uso do código acima é relativamente simples, use o Teclado para se registrar para monitorar a exibição e o estado oculto do teclado . Você pode ver o registro, o logout e a renderização do estado do evento do teclado serem colocados no Component.Se muita dessa lógica estiver envolvida no Component atual, ele fará com que o Component atual tenha responsabilidades muito pesadas e os dados do estado não poderão ser compartilhados. Quando você precisa monitorar eventos do teclado, é necessário reescrever ou copiar código duplicado.A redundância é muito séria e não é uma boa coisa para manutenção e expansão de funções.
O surgimento de Hooks resolve o problema acima: permite que os desenvolvedores definam componentes de função e também pode usar o estado e o ciclo de vida dos componentes de classe, sem a necessidade de alternar entre mixins, componentes de função, componentes HOC e objetos de renderização. Switch. É conveniente realizarmos a separação do código da lógica de negócios e a reutilização de componentes nos negócios. Comparado ao uso de setState, os componentes são sem estado. Vamos ver como usar Hooks:
import { useState, useEffect } from 'react';
import {
Keyboard
} from 'react-native';
export default function keyboard() {
const [keyboardStatus, setKeyboardStatus] = useState(false);
Keyboard.addListener(
"keyboardDidShow",
this.keyboardDidShowHandler
);
useEffect(()=> {
return ()=> Keyboard.removeListener(
"keyboardDidShow",
()=> setKeyboardStatus(true)
);
}, [false]);
return (
<Text>
当前键盘状态:{keyboardStatus}
</Text>
)
}
No código acima, a lógica de negócios sobre o teclado é desfeita em funções, chamadas componentes de função. Quando o usamos em outros componentes, precisamos apenas importá-lo. No componente function, usamos useState e useEffect.Que papel eles desempenham como APIs fornecidas no Hooks?
Hooks Api
O funcionário fornece três APIs principais de ganchos, como Ganchos de Estado, Ganchos de Efeito, Ganchos de Contexto, Ganchos Personalizados (ganchos personalizados).
useState
useState Esse método pode trazer o estado local para o componente de função, ele recebe um valor para o estado inicial e retorna um par de variáveis
// 等价于
const keyboardStatus= useState(0)[0];
const setKeyboardStatus= useState(0)[1];
É relativamente simples entender, de fato, é definir o valor do estado do estado e modificar a função de comportamento do valor do estado do estado.
useEffect
useEffect pode ser simplesmente entendido como um substituto para o seguinte ciclo de vida:
componentDidMount, componentDidUpdate, componentWillUnmount
O código de useEffect será executado não apenas durante a primeira inicialização (componentDidMount), mas também sempre que uma renderização subsequente for acionada (componentDidUpdate), e o valor de retorno será executado quando o componente não estiver registrado (componentWillUnmount). Combinado com o exemplo acima:
useEffect(()=> {
// return 将会在组件注销时调用
return ()=> Keyboard.removeListener(
"keyboardDidShow",
()=> setKeyboardStatus(true)
);
}, [false]);
O segundo parâmetro de useEffect, como uma configuração de otimização de desempenho, decide se é necessário executar as operações internas para evitar algumas perdas desnecessárias de desempenho. Enquanto o valor do membro na segunda matriz de parâmetros não for alterado, essa execução será ignorada. Se uma matriz vazia [] for passada, ela será executada apenas durante a montagem e desmontagem de componentes.
Ganchos de Contexto
Uma nova API de contexto foi lançada no React 16.3. O objetivo é resolver o problema de que o nível de aninhamento dos componentes filho é muito profundo e as propriedades dos componentes pai são difíceis de se comunicar. O método de uso não é complicado: primeiro, use a API de contexto para criar um provedor de dados (provedor) e um consumidor de dados (consumidor). (Falando nisso é um pouco como o exemplo da simultaneidade multithread Java). Armazene dados no local em que o provedor está localizado e busque os dados em que o consumidor está localizado. Dê uma olhada em como o Contexto é usado:
(1) Criar contexto
// 创建 Context
import React from 'react';
const DataContext = React.createContext({
name: '',
age: 23
});
export default DataContext;
(2) Defina o provedor do provedor de dados
export default class App extends Component {
render() {
return (
<DataContext.Provider value={{ name: 'Songlcy', age: 27 }}>
<CustomComponent />
</DataContext.Provider>
);
}
}
(3) Definir consumidor
export default class CustomComponent extends Component {
render() {
return (
<DataContext.Consumer>
{
context => (
<Text>
我的名字:{context.name}, 我的年龄:{context.age}
</Text>
)
}
</DataContext.Consumer>
)
}
}
Quando o nível de aninhamento de componentes for profundo, as vantagens do Contexto serão mais óbvias.
" Eh, acorde! " ... disse muito, continue voltando a Hooks. No código acima, os dados são obtidos do Contexto - Provedor - Consumidor , e todo o processo de valor é relativamente entediante. Quando queremos obter valores de vários consumidores , é ainda mais problemático aninhar funções.
useContext é uma simplificação da API de contexto. Vamos ver como fica depois da simplificação:
const { name, age } = useContext(DataContext);
" Eu confio! É este o fim? " Sim, o processo de valor é tão simples e caprichoso. Que tal mais 10 consumidores !
Ganchos personalizados
Ganchos personalizados é um comportamento de ganchos personalizado, que não é uma API em si. O conceito principal é extrair a lógica e encapsulá-la na função.A implementação específica é encapsular a lógica relacionada aos dados do estado (Estado) por meio de uma função e extrair essas lógicas do componente. Nesta função, podemos usar outros ganchos ou testá-lo separadamente. Modifique o exemplo acima:
export default function useKeyboardStatus() {
const [keyboardStatus, setKeyboardStatus] = useState(false);
Keyboard.addListener(
"keyboardDidShow",
this.keyboardDidShowHandler
);
useEffect(()=> {
return ()=> Keyboard.removeListener(
"keyboardDidShow",
()=> setKeyboardStatus(true)
);
},[]);
return keyboardStatus;
}
Código é quase idêntico, a única diferença é o nome da função com o uso * prefixo aqui precisa seguir uma convenção, chamado uso uso * .
Como funcionam os ganchos
"Shenma? Hooks é na verdade uma matriz !"
Lembre-se da maneira como usamos o useState inicialmente:
const [keyboardStatus, setKeyboardStatus] = useState(false);
De fato, a partir deste código, também podemos adivinhar a ideia geral de implementação:
Use uma função do tipo setter para retornar como o segundo item do array na função hook, e o setter controlará o estado gerenciado pelo hook (State), e o estado será retornado pelo primeiro item do array.
Podemos entender que existem duas matrizes, que armazenam respectivamente métodos correspondentes a state e setState.
Quando useState () é executado pela primeira vez, a função setter é enviada para a matriz setter e o estado é enviado para a matriz state. Cada setter tem uma referência à sua posição do cursor; portanto, ao acionar uma chamada para qualquer setter, ele altera o valor do estado nessa posição na matriz de estados. Para simplificar, existe um índice e o método setter modifica o valor dos dados do estado correspondente de acordo com o índice. Vamos dar uma olhada na implementação do pseudocódigo:
let state = []; // 存放state状态数据
let setter = []; // 存放 setXXX方法
let initial = true; // 是否是第一次运行
let index = 0;
useState(initVal) {
if (initial) {
state.push(initVal);
setter.push(createSetter(index));
initial = false;
}
const setter = setter[index];
const value = state[index];
index++;
return [value, setter];
}
createSetter(index) {
return function setterWithIndex(newVal) {
state[index] = newVal;
};
}
A implementação específica do código fonte, todos os interessados podem ir e ver. No entanto, não é recomendável entender todas as etapas, apenas entender a ideia de realização.
Sumário
O estado e a lógica de processamento relacionada podem ser divididos de acordo com a função, sem a necessidade de serem dispersos em cada ciclo de vida, o que reduz bastante a dificuldade de desenvolvimento e manutenção. Além desses ganchos, existem outros ganchos adicionais: Referência da API de ganchos
Por fim, recomende duas bibliotecas muito boas:
react-use : encapsula vários ganchos.
eslint-plugin-react-hooks : Ganchos ESLint 插件。
Um artigo muito bom sobre o React Native Hooks, escrito por um estrangeiro: Noções básicas sobre o React Hooks - Criando um aplicativo React Native com ganchos do React