Состояние реакции не определено, новое для реакции

#javascript #reactjs #react-native #websocket #django-channels

#javascript #reactjs #react-native #websocket #django-каналы

Вопрос:

Я новичок в react-native, я работаю над простым приложением, но по какой-то причине я продолжаю получать (undefined) для некоторых моих состояний, также при выборке данных сервер вызывается несколько раз со значением (undefined), прежде чем возвращать фактическое значение. Я искал довольно долго, но не нашел ничего, что помогло, поэтому я пришел сюда, чтобы попросить помощи у более продвинутых разработчиков React, чем я.

мой код выглядит так:

 const { data: chat, loading } = useApi(chatApi.getChat, { chatId: chatId, channelId: route.params.channelId });
const chatMessages = chat.messages  // I declared this only for testing
const [messages, setMessages] = useState(chatMessages);
console.log("Chat Messages: "   chatMessages)
console.log("messages State: "   messages)
 

В терминале я получаю:

 Chat Messages: undefined
messages State: undefined
Chat Messages: undefined
messages State: undefined
Chat Messages: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
messages State: undefined
 

Кроме того, почему переменная ‘chat’ отображается несколько раз со значением (undefined), прежде чем давать фактическое значение? Это привело к многократному вызову внутреннего сервера WS без каких-либо причин, что привело к снижению производительности

Перехват useApi:

 import { useEffect, useState } from "react";

const useApi = (apiFunc, funcParams ={}) => {
    const [data, setData] = useState([]);
    const [error, setError] = useState(false);
    const [loading, setLoading] = useState(false);

    const fetchData = async () => {
        setLoading(true);
        const response = await apiFunc(funcParams);
        setLoading(false);
        if (!response.ok) return setError(true);
        setData(response.data);
    };
    useEffect(() => { fetchData() }, []);
    if (data) return { data, setData, error, loading, setLoading };
};

export default useApi;
 

полный код

:

 const chatId = route.params.chat.id;
    const { data: chat, loading } = useApi(chatApi.getChat, { chatId: chatId, channelId: route.params.channelId });
    const { user } = useAuth();
    const [text, setText] = useState(() => { return ""; });
    const chatMessages = chat.messages  // I declared this only for testing
    const [messages, setMessages] = useState(chatMessages);
    console.log("Chat Messages: "   chatMessages)
    console.log("messages State: "   messages)

    const chatSocket = new WebSocket(`${settings.wsUrl}chat/${chatId}/?userId=${user.id}`);
    

    // Join amp; Leave Room
    useEffect(() => {
        chatSocket.onmessage = e => {
            const data = JSON.parse(e.data);
            setMessages([...messages, data.message]);
        };
        return () => {
            chatSocket.close(0);
        };
    }, []);

    const handleSendMessage = () => {
        chatSocket.send(JSON.stringify({
            text: text,
        }));
        setText("");
    };

    return (
        <>
            ...
        </>
 

Ответ №1:

Похоже, что вы получаете undefined во время загрузки данных (поскольку данных там еще нет, и поэтому они не определены), вы печатаете значение переменной всякий раз, когда компонент отображает, независимо от того, загружены ли данные.

У вас есть доступ к индикатору загрузки: const { data: chat, loading } но вы не используете переменную загрузки для чего-либо условного. Что-то вроде

 if (!loading amp;amp; data != null) {
   console.log("Chat Messages: "   chatMessages)
   console.log("messages State: "   messages)
   const chatSocket = new WebSocket(`${settings.wsUrl}chat/${chatId}/?userId=${user.id}`);
}
 

Комментарии:

1. Хорошо, это решило проблему многократного отображения, но почему состояние сообщений всегда не определено, в то время как переменная chatMessages присвоила значение один раз

2. useState — это перехват реакции, который сохраняет состояние между рендерами. Это означает, что при первом рендеринге вы предоставляете его chatMessages в качестве входных данных (chatMessages не определено при первом рендеринге, поскольку оно еще не загружено). При повторном рендеринге компонента React запоминает состояние chatMessages (не определено) и не сбрасывает его. Вам нужно вызвать setMessages после его загрузки. Вы могли бы сделать это несколькими способами. Внутри onEffect с загрузкой как зависимость, или вы можете просто удалить useState и использовать его как переменную, если оно вам не нужно как состояние