6

我想把它转换成一个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.

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

4

3 回答 3

11

那里有几件事。首先,要修复代码,您可以将您的代码更新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,它将完全取代状态值。反应文档说:

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

笔记2

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

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

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

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

关于 useEffect 的完整文章在这里

于 2019-05-22T04:19:10.767 回答
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
}, []);
于 2019-05-22T04:16:10.913 回答
1

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

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

于 2021-04-12T12:16:34.660 回答