#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 и использовать его как переменную, если оно вам не нужно как состояние