Реагировать — хук useEffect — componentDidMount для использованияEffect

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

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
7
0
24 792
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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 немного отличается от «старого» setState в том смысле, что полностью заменит значение состояния. Реагировать документация говорит:

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 меняет то, как мы создаем приложения, и это не настоящий «перевод» со старых жизненных циклов.

Пустые скобки ([]) в последней строке сделают ваш код «похожим» на componentDidMount, но самое главное, заставят ваш эффект выполняться только один раз.

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

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.

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

Я нашел альтернативное решение, которое не требует изменения 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;

Минус в том, что анимированные элементы не работают.

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