简体   繁体   中英

React - useEffect hook - componentDidMount to useEffect

I would like to convert this to an useEffect hook:

CODE

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

UPDATED CODE

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)});
  });
 })
}

Right now it's giving me a useState cannot be used in a callback .

How can I address this or convert this properly?

There are a couple of things there. First, to fix the code, you could update your useEffect to this:

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

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

Note 1

The setMessages line is how you update your state. useState is a little bit different from the "old" setState in a sense that will completely replace the state value. React documentation says:

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.

Note 2

React Hooks changes the way we build apps and it is not a real "translation" from the old lifecycles.

The empty brackets ( [] ) in the last line, will make your code "similar" to componentDidMount , but most importantly, will make your effect run only once.

Dan Abramov said (removed some of the original text):

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.

Full article about useEffect here .

You tried to declare the state again instead of using the state updater

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

I found an alternative solution that doesn't require modifying html. We create a higher order component that displays some waiting element and switch the state in componentDidMount or use effect in order to render the target component.

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;

The disadvantage is that the animated elements are not working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM