React - использовать крючок эффекта - componentDidMount для использования эффекта

Я хотел бы преобразовать это в 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,

Как я могу решить это или преобразовать это правильно?

3 ответа

Там есть пара вещей. Во-первых, чтобы исправить код, вы можете обновить 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, но самое главное, заставит ваш эффект работать только один раз.

Дан Абрамов сказал (убрал часть оригинального текста):

Хотя вы можете использовать Effect(fn, []), он не является точным эквивалентом. В отличие от componentDidMount, он будет захватывать реквизиты и состояния. Так что даже внутри обратных вызовов вы увидите начальный реквизит и состояние. (...) Имейте в виду, что ментальная модель эффектов отличается от componentDidMount и других жизненных циклов, и попытка найти их точные эквиваленты может сбить вас с толку больше, чем помочь. Чтобы стать продуктивным, вам нужно "мыслить эффектами", и их ментальная модель ближе к реализации синхронизации, чем к реагированию на события жизненного цикла.

Полная статья об использовании эффекта здесь.

Вы попытались объявить состояние снова вместо использования средства обновления состояния

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

Я нашел альтернативное решение, которое не требует модификации 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}
    </>
);

};

экспорт по умолчанию Загрузка;

Недостаток в том, что не работают анимированные элементы.

Другие вопросы по тегам