React - useEffect 钩子 - componentDidMount 到 useEffect

React - useEffect hook - componentDidMount to useEffect

我想将其转换为 useEffect 挂钩:

代码

componentDidMount () {
   this.messagesRef.on('child_added', snapshot => {
    const message = snapshot.val();
    message.key = snapshot.key;
    this.setState({messages: this.state.messages.concat(message 
  )});
});

更新代码

const MessageList = () => {
  const [messages, setMessage] = useState([]);
  const [usernames, setUsernames] = useState('');
  const [contents, setContents] = useState('');
  const [roomId, setRoomId] = useState('');

  const messagesRef = MessageList.props.firebase.database().ref('messages');

  useEffect(() => {
    messagesRef.on('child added', snapshot => {
    const message = snapshot.val();
    message.key = snapshot.key;

    const [messages, setMessages] = useState({messages: messages.concat(message)});
  });
 })
}

现在它给了我一个 useState cannot be used in a callback

我如何解决这个问题或正确转换它?

您试图再次声明状态而不是使用状态更新器

useEffect(() => {
  messagesRef.on('child added', snapshot => {
    const message = snapshot.val();
    message.key = snapshot.key;
    // setMessages is the state updater for messages
    // instead of an object with messages: messagesArray
    // just save it as an array the name is already messages
    setMessages([...messages, message]);
  });
// useEffect takes an array as second argument with the dependencies
// of the effect, if one of the dependencies changes the effect will rerun
// provide an empty array if you want to run this effect only on mount
}, []);

那里有一些东西。首先,要修复代码,您可以将 useEffect 更新为:

useEffect(() => {
    messagesRef.on('child added', snapshot => {
    const message = snapshot.val();
    message.key = snapshot.key;

    setMessages(messages.concat(message)); // See Note 1
}, []); // See Note 2

备注 1

setMessages 行是您更新状态的方式。 useState 在某种意义上与 "old" setState 有点不同,它将完全取代状态值。反应 documentation 说:

This is because when we update a state variable, we replace its value. This is different from this.setState in a class, which merges the updated fields into the object.

注2

React Hooks 改变了我们构建应用程序的方式,它不是旧生命周期的真实"translation"。

最后一行的空括号 ([]) 将使您的代码 "similar" 变为 componentDidMount,但最重要的是,只会使您的效果 运行一次。

Dan Abramov 说(删除了部分原文):

While you can useEffect(fn, []), it’s not an exact equivalent. Unlike componentDidMount, it will capture props and state. So even inside the callbacks, you’ll see the initial props and state. (...) Keep in mind that the mental model for effects is different from componentDidMount and other lifecycles, and trying to find their exact equivalents may confuse you more than help. To get productive, you need to “think in effects”, and their mental model is closer to implementing synchronization than to responding to lifecycle events.

关于 useEffect 的完整文章 here

我找到了一个不需要修改的替代解决方案 html。我们创建一个显示一些等待元素的高阶组件,并在 componentDidMount 中切换状态或使用效果来渲染目标组件。

import React, { useEffect, useState } from 'react';
const Loading = (props) => {

    const [loading, setLoading] = useState(true);

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

    return (
        <>
            {loading ?
            <div style={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                width: '100%',
                height: '100%',
                fontSize: '5vh'
            }}>
                Loading...
            </div> :
            props.children}
        </>
    );

};

export default Loading;

缺点是动画元素不起作用