componentDidMount equivalente em uma função React / componente Hooks?

107

Existem maneiras de simular componentDidMountcomponentes funcionais do React por meio de ganchos?

Jeyko
fonte

Respostas:

216

Para a versão estável dos ganchos (React versão 16.8.0+)

Para componentDidMount

useEffect(() => {
  // Your code here
}, []);

Para componentDidUpdate

useEffect(() => {
  // Your code here
}, [yourDependency]);

Para componentWillUnmount

useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

Portanto, nesta situação, você precisa passar sua dependência para este array. Vamos supor que você tenha um estado como este

const [count, setCount] = useState(0);

E sempre que a contagem aumenta, você deseja renderizar novamente o componente de função. Então você useEffectdeve se parecer com isto

useEffect(() => {
  // <div>{count}</div>
}, [count]);

Dessa forma, sempre que sua contagem for atualizada, seu componente será renderizado novamente. Espero que isso ajude um pouco.

Mertcan Diken
fonte
Explicação completa! Existe uma maneira de simular o componentDidReceiveProps?
jeyko
1
Não estou ciente disso, mesmo que exista. Você pode verificar este tópico em github.com/facebook/react/issues/3279
Mertcan Diken
1
Obrigado por isso, pois eu não estava ciente do segundo argumento em useState. Para quem undefinedestiver lendo isso, lembre-se de que deixar o segundo argumento fará com que seu efeito seja acionado em cada renderização (se não estou enganado).
dimiguel
Você quer dizer dependências de useEffect (passando uma matriz de dependência)? Se sim, se você deixar vazio, isso é um bug no código. Para a desconstrução da matriz, você precisa de [count, setCount] porque count é sua variável de estado neste exemplo e setCount é sua função para atualizar esse estado.
Mertcan Diken
1
Tenho tentado usar a matriz de dependência vazia para simular o componentDidMount. O problema é que geralmente resulta em um aviso: "React Hook useEffect tem uma dependência ausente: <some prop>. Inclua-a ou remova a matriz de dependência react-hooks / exaustive-deps". Aplicar qualquer uma das "correções" sugeridas faz com que ele não se comporte mais como componentDidMount. Estou fazendo algo errado?
Jonas Rosenqvist
3

Embora a resposta aceita funcione, não é recomendada. Quando você tem mais de um estado e o usa com useEffect, ele avisa sobre como adicioná-lo ao array de dependências ou não usá-lo.

Às vezes, causa problemas que podem gerar resultados imprevisíveis. Portanto, sugiro que você se esforce um pouco para reescrever sua função como classe. Existem muito poucas mudanças, e você pode ter alguns componentes como classe e alguns como função. Você não é obrigado a usar apenas uma convenção.

Veja isso por exemplo

function App() {
  const [appointments, setAppointments] = useState([]);
  const [aptId, setAptId] = useState(1);

  useEffect(() => {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = aptId;
          console.log(aptId);
          setAptId(aptId + 1);
          return item;
        })
        setAppointments(apts);
      });
  }, []);

  return(...);
}

e

class App extends Component {
  constructor() {
    super();
    this.state = {
      appointments: [],
      aptId: 1,
    }
  }

  componentDidMount() {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = this.state.aptId;
          this.setState({aptId: this.state.aptId + 1});
          console.log(this.state.aptId);
          return item;
        });
        this.setState({appointments: apts});
      });
  }

  render(...);
}

Isso é apenas por exemplo . portanto, não vamos falar sobre as melhores práticas ou possíveis problemas com o código. Ambos têm a mesma lógica, mas o último funciona apenas conforme o esperado. Você pode obter a funcionalidade componentDidMount com useEffect em execução neste momento, mas conforme seu aplicativo cresce, há chances de que você possa enfrentar alguns problemas. Portanto, em vez de reescrever nessa fase, é melhor fazer isso no estágio inicial.

Além disso, OOP não é tão ruim assim, se a Programação Orientada a Procedimentos fosse suficiente, nunca teríamos tido a Programação Orientada a Objetos. É doloroso às vezes, mas melhor (tecnicamente. Questões pessoais à parte).

Aniket Kariya
fonte
1
Eu fiz isso. Eu enfrentei problema usando ganchos. O problema desapareceu depois de convertê-lo em classe.
Julez
2

Não há componentDidMountcomponentes funcionais, mas os Ganchos React fornecem uma maneira de emular o comportamento usando o useEffectgancho.

Passe uma matriz vazia como o segundo argumento useEffect()para executar apenas o retorno de chamada na montagem.

Por favor, leia a documentação emuseEffect .

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

Yangshun Tay
fonte
1

Não há equivalente exato para componentDidMountganchos de reação.


Na minha experiência, os hooks react requerem uma mentalidade diferente ao desenvolvê-los e, de modo geral, você não deve compará-los aos métodos de classe como componentDidMount.

Com isso dito, há maneiras de usar ganchos para produzir um efeito semelhante ao componentDidMount.

Solução 1:

useEffect(() => {
  console.log("I have been mounted")
}, [])

Solução 2:

const num = 5

useEffect(() => {
  console.log("I will only run if my deps change: ", num)
}, [num])

Solução 3 (com função):

useEffect(() => {
  const someFunc = () => {
    console.log("Function being run after/on mount")
  }
  someFunc()
}, [])

Solução 4 (useCallback):

const msg = "some message"

const myFunc = useCallback(() => {
  console.log(msg)
}, [msg])

useEffect(() => {
  myFunc()
}, [myFunc])

Solução 5 (ser criativo):

export default function useDidMountHook(callback) {
  const didMount = useRef(null)

  useEffect(() => {
    if (callback && !didMount.current) {
      didMount.current = true
      callback()
    }
  })
}

É importante notar que a solução 5 só deve ser usada realmente se nenhuma das outras soluções funcionar para seu caso de uso . Se você decidir que precisa da solução 5, recomendo usar este gancho pré-fabricado use-did-mount .

Fonte (com mais detalhes): Usando componentDidMount em react hooks

Atomitos
fonte
0

o gancho equivalente exato para componentDidMount () é

useEffect(()=>{},[]);

espero que seja útil :)

Aravinth
fonte
-1

Você deseja usar useEffect(), que, dependendo de como você usa a função, pode atuar como componentDidMount ().

Por exemplo. você pode usar uma loadedpropriedade de estado customizada que é inicialmente definida como false e alterná-la para true na renderização e apenas disparar o efeito quando esse valor mudar.

Documentação

markmoxx
fonte
1
Esta solução não é ideal. É uma má ideia usar um valor de estado apenas para determinar se o componente foi montado. Além disso, se você fosse usar uma propriedade, um ref seria melhor, pois não acionaria outra renderização.
Yangshun Tay