Comece com os ganchos React, compare os componentes da classe para aprender useState e useEffect [prática, resumo]

A experiência do blogger ainda é superficial, corrija-me se houver algum erro

Um: useState

1. Como usar

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

Como pode ser visto no código-fonte da definição de gancho acima, o parâmetro da função de gancho useState é passado em um valor inicial (ou uma função que obtém o valor inicial após a chamada), e o valor de retorno é retornado ao mundo externo para operações de leitura e gravação no estado (na forma de uma matriz) . O exemplo de uso básico é o seguinte:

const [state, setState] = useState(initialState);

2. Caso de uso

Como todos sabemos, os componentes da classe também são chamados de componentes com estado e têm a capacidade de gerenciar o estado. Antes que a função de gancho apareça, o componente de função também é chamado de componente sem estado e não tem a capacidade de gerenciar o estado. Até que a função de gancho apareça, o componente de função tem a capacidade de gerenciar o estado. A seguir está uma lista das diferenças na implementação do gerenciamento de estado entre componentes de classe e componentes de função (com useState). Preste atenção à inicialização do estado e às operações de leitura e gravação do estado dessas duas maneiras .

Status de gerenciamento de componente de classe
import React from "react";

export default class ClassComp extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.state = {
    
    
      count: 0
    };
  }

  render() {
    
    
    return (
      <div>
        <p>You clicked {
    
    this.state.count} times (classComp)</p>
        <button onClick={
    
    () => this.setState({
    
     count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
Estado de gerenciamento do componente de função (useState)
import React, {
    
     useState } from "react";

export default function FuncComp() {
    
    
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {
    
    count} times (FuncComp)</p>
      <button onClick={
    
    () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

3. Detalhes de uso

(1) Estado inicial lento [Otimização de desempenho: initialState calculado por fn, como useState (fn)]

O parâmetro initialState só funcionará na renderização inicial do componente e será ignorado nas renderizações subsequentes. Se o estado inicial precisa ser obtido por meio de cálculos complexos, você pode passar uma função, calcular e retornar o estado inicial da função, esta função só é chamada durante a renderização inicial:

  • Método indesejável 1, initialState será calculado a cada renderização, o que desperdiça desempenho.
const initialState = someExpensiveComputation(props);
const [state, setState] = useState(initialState);
  • Modo preferido 2: ao passar uma função, a função de cálculo do valor inicial é chamada apenas uma vez.
const [state, setState] = useState(() => {
    
    
  const initialState = someExpensiveComputation(props);
  return initialState;
});
(2) Atualização funcional [otimização de codificação: updateState calculado por fn, como setXxx (fn)]

Se o novo estado precisar ser calculado usando o estado anterior, a função pode ser passada para setState. Esta função receberá o estado anterior e retornará um valor atualizado. O seguinte exemplo de componente de contador mostra dois usos de setState:

function Counter({
    
    initialCount}) {
    
    
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {
    
    count}
      <button onClick={
    
    () => setCount(initialCount)}>Reset</button>
      <button onClick={
    
    () => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={
    
    () => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
(3) Pule a atualização de estado [Resolva a dúvida: se a mesma atualização de valor é considerada uma mudança de estado]

Ao chamar a função de atualização do State Hook e passar no estado atual, o React irá pular a renderização dos componentes filhos e a execução do efeito . (React usa o algoritmo de comparação Object.is para comparar o estado.)

  • Este é o algoritmo de comparação como segue, pelo que se segue pode-se concluir inicialmente que podemos usar o uso básico da regra de julgamento de endereço para julgar.
Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var foo = {
    
     a: 1 };
var bar = {
    
     a: 1 };
Object.is(foo, foo);         // true
Object.is(foo, bar);         // false

Object.is(null, null);       // true

// 特例
Object.is(0, -0);            // false
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

Dois: useEffect

1. Como usar

 function useEffect(effect: EffectCallback, deps?: DependencyList): void;

Como pode ser visto no código-fonte da definição de gancho acima, o parâmetro 1 da função de gancho useEffect é passado em uma função de retorno de chamada de efeito colateral e o parâmetro 2 é passado em uma matriz de dependência de efeitos colaterais (opcional) e não há valor de retorno. O exemplo de uso básico é o seguinte:

  // componentDidMount or componentDidUpdate && count state change
  useEffect(() => {
    
    
    console.log(count)
  },[count])

2. Caso de uso

Efeitos colaterais do componente de classe
import React from "react";

export default class ClassComp extends React.Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      count: 0
    };
  }

  componentDidMount() {
    
    
    console.log('class', 'componentDidMount')
  }

  componentWillUpdate(nextProps, nextState) {
    
    
    console.log('class', 'componentWillUpdate')
    if(this.state.count !== nextState.count)console.log(this.state.count)
  }

  componentDidUpdate(prevProps, prevState) {
    
    
    console.log('class', 'componentDidUpdate')
    if(this.state.count !== prevState.count)console.log(this.state.count)
  }

  componentWillUnmount() {
    
    
    console.log('class', 'componentWillUnmount')
  }
  render() {
    
    
    return (
      <div>
        <p>You clicked {
    
    this.state.count} times (classComp)</p>
        <button onClick={
    
    () => this.setState({
    
     count: this.state.count + 1 })}>
          Click me
      </button>
      </div>
    );
  }
}
Efeitos colaterais do componente de função (useEffect)
import React, {
    
     useState, useEffect } from "react";

export default function FuncComp() {
    
    
  const [count, setCount] = useState(0)

  // 等同于:componentDidMount
  useEffect(() => {
    
    
    console.log('function', 'componentDidMount')
  }, [])

  // 等同于:componentDidMount or componentDidUpdate
  useEffect(() => {
    
    
    console.log('function', 'componentDidMount or componentDidUpdate')
  })

  // 等同于:(componentDidMount or componentDidUpdate) && count state change
  useEffect(() => {
    
    
    console.log('function', 'componentDidUpdate console newCount', count)
  }, [count])

  // 等同于:componentWillUpdate or componentWillUnmount
  useEffect(() => {
    
    
    return () => {
    
    
      console.log('function', 'componentWillUpdate or componentWillUnmount')
    }
  })

  // 等同于:(componentWillUpdate or componentWillUnmount ) && count state change
  useEffect(() => {
    
    
    return () => {
    
    
      console.log('function', 'componentWillUpdate or componentWillUnmount console preCount', count)
    }
  }, [count])

  // 等同于:componentWillUnmount
  // useEffect(() => {
    
    
  //   return () => {
    
    
  //     console.log('function', 'componentWillUnmount')
  //   }
  // },[])

  // 等同于:(componentDidMount or componentDidUpdate) and (componentWillUpdate or componentWillUnmount)
  // useEffect(() => {
    
    
  //   console.log('function', 'componentDidMount or componentDidUpdate')
  //   return () => {
    
    
  //     console.log('function', 'componentWillUpdate or componentWillUnmount')
  //   }
  // })
  return (
    <div>
      <p>You clicked {
    
    count} times (FuncComp)</p>
      <button onClick={
    
    () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
resultado da operação
  • A montagem
    Insira a descrição da imagem aqui
    pode ser vista nos resultados de execução acima. Depois que o componente é montado: apenas o método de ciclo de vida componentDidMount do componente de classe é executado e toda a lógica de efeito colateral do componente de função é executada (há apenas três consoles porque os dois últimos useEffects são apenas registrados Antes de atualizar e desinstalar a lógica).
  • A atualização
    Insira a descrição da imagem aqui
    pode ser vista a partir dos resultados de execução acima, após o componente ser atualizado: os métodos de ciclo de vida componentWillUpdate e componentDidUpdate do componente de classe são executados, e toda a lógica de efeitos colaterais do useEffect do componente de função são todos efeitos colaterais, exceto para a primeira matriz de dependência registrada que está vazia. A lógica é executada (não há efeitos colaterais dependendo da matriz também executada).
  • Descarregando
    Insira a descrição da imagem aqui
    A partir dos resultados de execução acima, pode-se ver que depois que o componente é descarregado: o método de ciclo de vida componentWillUnMount do componente de classe é executado e toda a lógica de efeito colateral de useEffect do componente de função é executada se a lógica de desinstalação for registrada.

3. Detalhes de uso

(1) Condição de disparo da lógica de efeito colateral de uso

Por padrão, o efeito será executado após cada rodada de renderização, mas pode ser executado apenas quando certos valores mudam passando na matriz de dependência.

(2) O tempo de execução depois que a lógica de efeito colateral useEffect é acionada

Diferente de componentDidMount e componentDidUpdate, depois que o navegador completa o layout e desenho, a função passada para useEffect será chamada mais tarde.

(3) Limpeza da lógica de efeito colateral useEffect [para evitar vazamentos de memória]

Normalmente, quando o componente é desinstalado, é necessário limpar recursos como assinatura ou ID do cronômetro criado pelo efeito (como no sexto useEffect no exemplo acima). Para evitar vazamentos de memória, a função de limpeza será executada antes que o componente seja descarregado.
Além disso, se o componente for renderizado várias vezes (normalmente), o efeito anterior é limpo antes que o próximo efeito seja executado (como no quarto / quinto useEffect no exemplo acima).

4. Restam dúvidas

A partir do exemplo acima, podemos descobrir que os ganchos useEffect podem simular a implementação separada dos dois ciclos de vida de willMount e unMount no componente de classe e também podem simular a combinação de willMount e DidUpdate, a combinação de unMount e willUpdate, e willMount e DidUpdate. , UnMount, willUpdate combinação de quatro. Mas há um problema, como posso simular um método de ciclo de vida separado DidUpdate ou WillUpdate? No desenvolvimento real, encontrei essa demanda. Como não encontrei uma solução adequada, poupei a implementação do Wanzi e eliminei o estado de montagem julgando um determinado estado de sinalização que está disponível apenas na fase de atualização. A lógica de efeito colateral só é executada durante DidUpdate e não durante DidMount. Se existe uma maneira melhor de olhar para as pessoas, por favor me avise, obrigado!

Acho que você gosta

Origin blog.csdn.net/jw2268136570/article/details/108766428
Recomendado
Clasificación