【问题标题】:React - useEffect hook - componentDidMount to useEffectReact - useEffect hook - componentDidMount to useEffect
【发布时间】:2019-10-08 11:44:38
【问题描述】:

我想将其转换为 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

我怎样才能解决这个问题或正确转换它?

【问题讨论】:

    标签: reactjs use-effect


    【解决方案1】:

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

    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
    }, []);
    

    【讨论】:

      【解决方案2】:

      那里有几件事。首先,要修复代码,您可以将 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 与“旧”setState 在某种意义上有点不同,它将完全取代状态值。 React documentation 说:

      这是因为当我们更新状态变量时,我们会替换它的值。这与类中的 this.setState 不同,后者将更新的字段合并到对象中。

      注2

      React Hooks 改变了我们构建应用程序的方式,它并不是对旧生命周期的真正“翻译”。

      最后一行中的空括号 ([]) 将使您的代码与componentDidMount“相似”,但最重要的是,将使您的效果只运行一次。

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

      虽然您可以使用Effect(fn, []),但它并不是完全等价的。与 componentDidMount 不同,它将捕获道具和状态。所以即使在回调中,你也会看到初始的 props 和 state。 (...) 请记住,效果的心理模型与 componentDidMount 和其他生命周期不同,试图找到它们的确切等价物可能会让您感到困惑,而不是帮助。为了提高工作效率,您需要“思考效果”,他们的心智模型更接近于实现同步,而不是响应生命周期事件。

      关于useEffect的完整文章here

      【讨论】:

        【解决方案3】:

        我找到了一个不需要修改 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;
        

        缺点是动画元素不起作用。

        【讨论】:

          猜你喜欢
          • 2020-11-21
          • 2021-02-23
          • 2020-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-24
          • 2021-01-16
          • 2019-08-09
          相关资源
          最近更新 更多