@Ex1st

Бесконечный цикл useEffect?

Из родительского компонента приходит массив с отправленными сообщениями. Проблема в том, что в useEffect вызывается setState и рендер циклится.

export const UserMessages = (props) => {
    const connection = props.connection;
    const newSendedMessage = props.arSendedMessage;

    const [added, setAdded] = useState(false);
    const [sendedMsg, setSendedMsg] = useState([]);
    const [receivedMsg, setReceivedMsg] = useState([]);
    const [arUsersMessages, setArUsersMessages] = useState([]);

    useEffect(() => {
        setSendedMsg(newSendedMessage);
        sortMessages();
    });

    connection.onmessage = function (event) {
        handlerReceivedMessage(event);
    }

    function sortMessages() {
        let arMess = sendedMsg.concat(receivedMsg);

        arMess.sort((a, b) => (a.date > b.date) ? 1 : -1)

        console.log(arMess);

        if (arMess == arUsersMessages)
            return;
        else {
            setArUsersMessages(arMess);
        }
    }


Пробовал вот так, не помогло:
useEffect(() => {
        if (loaded) 
            return;
        
        setSendedMsg(newSendedMessage);
        sortMessages();

        setLoaded(true);
    }, [loaded]);


Компонент не рендерится, когда данные изменяются

Еще пробовал вот так:
useEffect(() => {
        if (loaded)
            return;

        setSendedMsg(newSendedMessage);
        sortMessages();

        setLoaded(true);
    });


Тоже самое
  • Вопрос задан
  • 1242 просмотра
Пригласить эксперта
Ответы на вопрос 2
black1277
@black1277
Вольный стрелок
Всё от того, что вы не желаете знать про жизненный цикл компонентов. Разберем по порядку, что происходит.
1 компонент смонтировался
2 срабатывает useEffect - он всегда срабатывает после того как готово DOM дерево.
3 в useEffect срабатывает useState
4 изменение состояния обязывает реакт сделать ререндер
5 тут ключевой момент, компонент уже был смонтирован, поэтому происходит только его обновление - и вот тут useEffect ведет себя по разному. Если у него нет массива зависимостей - то он опять сработает и всё будет повторятся с 3-го пункта. Если же у него есть массив зависимостей - то он сработает только если после рендера обновления изменилось значение в этом массиве.
Значит вам нужно как минимум указать newSendedMessage в этом массиве. НО! У вас есть и другая функция, которая изменяет стейт - sortMessages. Её тоже нужно указать в массиве зависимостей, если не хотите пропускать обновление при изменении receivedMsg. Но если просто поместить эту ф-ю в массив зависимостей - то опять получите бесконечный перерендер - потому что ф-я каждый раз будет разная (она пересоздается каждый раз во время обновления). Есть разные варианты как это исправить - или завернуть sortMessages в useCallback (у которого должен быть массив зависимостей с receivedMsg) или перенести саму ф-ю sortMessages внутрь useEffect и вызывать там. Тут вам решать какой вариант подходит логике вашего компонента больше.
Ответ написан
Alexandroppolus
@Alexandroppolus
кодир
Как минимум, внутри sortMessages всегда вызывается setArUsersMessages(arMess), потому как массивы не равны по ссылке. Это приводит к перерендеру.

А вообще, много чего странного в коде. Например, сообщения есть и в props.arSendedMessage, и в стейте компонента. Выглядит как полная анархия (мать порядка).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы