#javascript #reactjs #react-hooks #use-effect #use-state
#javascript #reactjs #реагирующие перехваты #use-effect #use-state
Вопрос:
Что я пытаюсь сделать?
Рендеринг characterInfo
с помощью реактивных перехватов во внешнем интерфейсе.
Какой код в настоящее время пытается это сделать?
Интерфейсный компонент отображает информацию:
export default function ReactComponent() {
const [characterInfo, setCharacterInfo] = useState([]);
useEffect(() => {
socket.emit("/character/read");
socket.on("/character/read", function (data) {
if (data.status === "SUCCESS") {
setCharacterInfo(data)
}
});
return () => {
socket.off("/character/read");
};
}, []);
return (
<div>
{characterInfo.models[0].name}
</div>
)
}
Внутренняя .json
информация как «данные», а также то, что сохраняется с characterInfo
помощью setCharacterInfo
:
{
status: "SUCCESS"
models: [
{
name: "AC",
element: "Air",
}
{
name: "Irene",
element: "Fire",
}
]
}
(так что в этом случае для доступа к «AC» это было бы characterInfo.models[0].name
)
Каким я ожидаю результата?
Я ожидаю, что оно просто AC
будет отображено.
Каков фактический результат?
Я бы получил эту ошибку:
TypeError: Cannot read property '0' of undefined
В чем, я думаю, может быть проблема?
Я думаю, что это связано с асинхронной балансировкой, особенно с useEffect()
. Я думаю, что интерфейс пытается выполнить рендеринг, прежде setCharacterInfo
чем решит что-либо установить.
Комментарии:
1. Вам нужно просмотреть свои результаты. С помощью чего-то вроде «map’ при его рендеринге
2. Кроме того, ваши данные настройки как часть вашего состояния, когда для вашего состояния установлено значение characterInfo
3. Для первого комментария, если вы говорите
{characterInfo.models.map((model) => (<div>{model.name}</div>))}
, ошибка, которую я получу, относитсяTypeError: Cannot read property 'map' of undefined'.
ко второму комментарию, да, я помещаю «данные» вsetCharacterInfo
состояние, тогда «данные» должны быть моимcharacterInfo
состоянием.
Ответ №1:
Я думаю, что интерфейс пытается выполнить рендеринг до того, как setCharacterInfo решит вообще что-либо установить.
Это правильно, ваш компонент отображается один раз со useState
значением по умолчанию перед запуском функции useEffect
. Вот диаграмма порядка выполнения при подключении, обновлении и отключении компонента (примечание render
происходит раньше useEffect
):
https://raw.githubusercontent.com/donavon/hook-flow/master/hook-flow.png
Вам нужно будет проверить, characterInfo.models
существует ли оно (и, чтобы быть в безопасности, убедитесь, что оно имеет длину) перед доступом name
.
return (
<div>
{
characterInfo.models amp;amp;
characterInfo.models.length amp;amp;
characterInfo.models[0].name
}
</div>
)
Или, если вы используете необязательную цепочку:
return (
<div>
{characterInfo?.models[0]?.name}
</div>
)
Еще одно замечание — вы устанавливаете начальное значение characterInfo
в пустой массив. Если вы сделаете его пустым объектом, будет яснее, что вы ожидаете data
быть объектом, а не массивом.
const [characterInfo, setCharacterInfo] = useState({});
Комментарии:
1. Я попробовал первое решение, и интерфейс ничего не отображал. Я сделал a
console.log
для каждого из значений, и вот что последовало :[{...}], undefined, "AC"
. Теперь, когда я попробовал просто{characterInfo.models amp;amp; characterInfo.models[0].name}
, это сработало! Я попробовал второе решение, и это привело к той же проблемеTypeError: Cannot read property '0' of undefined
. Я пошел дальше и сделал вашу заметку, которую, на мой взгляд, полезно использовать. Спасибо за вашу помощь!
Ответ №2:
Вы можете настроить свой оператор return так, чтобы отображать имя только в том случае, если / когда оно существует
return (
<div>
{characterInfo.length amp;amp; characterInfo.models[0].name}
</div>
)
Комментарии:
1. Решение не сработало для меня, я углубился, чтобы посмотреть, какие значения отображаются с помощью кнопки, которая
console.log(characterInfo.length)
иconsole.log(characterInfo.models[0].name)
, первая будет отображатьсяundefined
, а вторая будет отображаться"AC"
. Спасибо за попытку!