ReactJS 16.13.1 Когерентное состояние в слушателе - PullRequest
0 голосов
/ 09 апреля 2020

Я не понимаю, какие маги c действуют здесь, я пытаюсь все вспомнить, я не могу решить эту проблему.

Я хочу использовать массив, который находится в реагировать на состояние моего компонента в слушателе веб-сокета, когда слушатель срабатывает, мое состояние - пустой массив, однако я устанавливаю значение в useEffect.

Вот мой код:

function MyComponent() {
    const [myData, setMyData] = useState([]);
    const [sortedData, setSortedData] = useState([]);

    useEffect(() => {
        someAxiosCallWrapped((response) => {
            const infos = response.data;
            setMyData(infos.data);
            const socket = getSocket(info.socketNamespace); // wrap in socket namespace
            handleEvents(socket);
        });
    }, []);


    useEffect(() => {
        setSortedData(sortTheArray(myData));
    }, [myData]);

    const handleEvents = (socket) => {
        socket.on('EVENT_NAME', handleThisEvent);
    };

    const handleThisEvent = payload => {
        const myDataCloned = [...myData]; //<=== my probleme is here, whatever I've tried myData is always an empty array, I don't understand why
        /**
         * onHandleEvent is an external function, just push one new object in the array no problem in the function
         */
        onHandleEvent(myDataCloned, payload);
        setMyData(myDataCloned);
    };

    return (
        <div>
            // display sortedData no problem here
        </div>
    );
}

Вероятно, пропустил что-то очевидное, если кто-то увидит что.

Спасибо!

Ответы [ 3 ]

2 голосов
/ 09 апреля 2020

Из документов :

Любая функция внутри компонента, включая обработчики событий и эффекты, «видит» реквизиты и состояние из рендера, в котором он был создан.

Здесь handleEvents вызывается с useEffect при монтировании и, следовательно, он видит только исходные данные ([]). Чтобы лучше уловить эту ошибку, мы можем переместить функции внутрь useEffect (если это абсолютно не нужно)

useEffect(() => {
  const handleEvents = (socket) => {
    socket.on('EVENT_NAME', handleThisEvent);
  };

  const handleThisEvent = payload => {
      const myDataCloned = [...myData];
      onHandleEvent(myDataCloned, payload);
  };

  someAxiosCallWrapped((response) => {
    const infos = response.data;
    setMyData(infos.data);
    const socket = getSocket(info.socketNamespace); // wrap in socket namespace
    handleEvents(socket);
  });

  return () => {
    socket.off('EVENT_NAME', handleThisEvent);
  }
}, [myData, onHandleEvent]);

Теперь вы можете видеть, что useEffect имеет зависимости от myData и onHandleEvent , Мы не вводили эту зависимость сейчас, у нее уже были эти, мы просто видим их более четко сейчас.

Также обратите внимание, что мы удаляем слушателя при изменении useEffect. Если onHandleEvent изменяется при каждом рендеринге, вы должны заключить его в useCallback в родительском компоненте.

Безопасно ли опускать функцию из зависимостей - Документы

0 голосов
/ 10 апреля 2020

Я наконец придумаю такой код.

useEffect(() => {
  let socket;
  someAxiosCallWrapped((response) => {
    const infos = response.data;
    setMyData(infos.data);
    socket = getSocket(info.socketNamespace); // wrap in socket namespace
    setSocket(socket)

  });

  return () => {
    if(socket) {
        socket.disconnect();
    }
  }
}, []);

useEffect(() => {
    if(socket) {
        const handleEvents = (socket) => {
        socket.off('EVENT_NAME').on('EVENT_NAME', handleThisEvent);
      };

      const handleThisEvent = payload => {
          const myDataCloned = [...myData];
          onHandleEvent(myDataCloned, payload);
      };
    }
}, [socket, myData, onHandleEvent]);

Спасибо Агни!

0 голосов
/ 09 апреля 2020

вам нужно использовать ловушку useMemo для обновления функции после изменения значения массива, если только компонент Hooks не будет всегда использовать значение начального состояния. замените проблемную часть на эту и попробуйте

const handleThisEvent = useMemo(payload => {
       const myDataCloned = [...myData]; 
       onHandleEvent(myDataCloned, payload);
       setMyData(myDataCloned);
   },[the values you need to look for(In this case myData)]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...