У меня есть этот код React:
import React, { useState, useEffect } from "react";
import axios from "axios";
function App() {
const [players, setPlayers] = useState([]);
// Get all Players
const getAllPlayersUrl = "http://localhost:5087/api/GetAllPlayers";
useEffect(() => {
axios.get(getAllPlayersUrl).then((response) => {
setPlayers(response.data);
});
}, []);
const [playerCount, setPlayerCount] = useState(players.length);
return (
<div>
<p>{`This is how many there are: ${playerCount}`}</p>
</div>
);
}
export default App;
Я хочу напечатать, сколько начальных игроков, используя переменную playerCount. Однако он говорит, что это ноль:
Вот сколько их: 0
Если я вместо этого напечатаю players.length, он выведет правильное число:
<p>{`This is how many there are: ${players.length}`}</p>
Вот сколько их: 9
Даже если я удалю массив зависимостей, чтобы продолжить рендеринг, playerCount все равно не будет обновляться:
useEffect(() => {
axios.get(getAllPlayersUrl).then((response) => {
setPlayers(response.data);
});
});
Интересно, почему useState не работает? Есть ли что-то, что мне не хватает в моем коде?
Значение, которое вы передаете в useState, актуально только в первый раз по умолчанию. Зачем вообще использовать playerCount? Просто получите доступ к player.length там, где вам это нужно.
Я не думаю, что мне нужно вызывать setPlayerCount, так как я не меняю playerCount. Я просто получаю его начальный счет, который уже инициализирован player.length
@jonrsharpe, потому что я хочу изменить playerCount в будущем.
Независимо от длины списка? Тогда почему то, что происходит прямо сейчас, является проблемой?
@jonrsharpe да, независимо от списка. Это проблема прямо сейчас, потому что она не работает, и я хотел бы знать, почему.
Сейчас он не зависит от списка: вы никогда его не обновляете, он никогда не меняется. Вы говорите, что это неправильно, и хотите, чтобы это была длина списка, так что... используйте длину списка. У вас не может быть и того, и другого.
@jonrsharpe Мой главный вопрос был «почему это не работает?». Ответ ниже помог мне понять, что когда состояние было инициализировано, players было пустым, и я никогда не обновлял его, поэтому да, это всегда будет 0. Это действительно все, что я искал. Если мне действительно нужно просто получить размер массива, я мог бы просто это сделать. Но я работаю над кодом, в котором я отслеживаю «Выбранные элементы» в этом массиве, поэтому я не могу просто использовать размер массива, поскольку «Выбранные элементы» будут постоянно меняться. Итак, я столкнулся с этой проблемой, отсюда и вопрос «почему это не работает?»



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Хорошее эмпирическое правило для состояния (и свойств) — избегать дублирования значений состояния, когда значение может быть полностью определено другим. В противном случае вы можете столкнуться с подобными проблемами, когда синхронизация нескольких состояний может быть более сложной, чем должна быть.
Здесь вы устанавливаете начальное значение playerCount при монтировании компонента:
const [playerCount, setPlayerCount] = useState(players.length);
И компонент монтируется только один раз - и в это время players является пустым массивом - поэтому playerCount становится 0, и, поскольку вы никогда не вызываете setPlayerCount, он всегда остается 0.
Хотя вы можете исправить это, вызвав setPlayerCount внутри вашего .then, лучшим подходом будет либо вычисление количества игроков из состояния players только при необходимости:
function App() {
const [players, setPlayers] = useState([]);
const getAllPlayersUrl = "http://localhost:5087/api/GetAllPlayers";
useEffect(() => {
axios.get(getAllPlayersUrl).then((response) => {
setPlayers(response.data);
});
}, []);
return (
<div>
<p>{`This is how many there are: ${players.length}`}</p>
</div>
);
}
Или, если очень надо, запомнить счётчик в зависимости от массива players (без создания дополнительного состояния).
function App() {
const [players, setPlayers] = useState([]);
const playerCount = useMemo(() => players.length, [players]);
const getAllPlayersUrl = "http://localhost:5087/api/GetAllPlayers";
useEffect(() => {
axios.get(getAllPlayersUrl).then((response) => {
setPlayers(response.data);
});
}, []);
return (
<div>
<p>{`This is how many there are: ${playerCount}`}</p>
</div>
);
}
Спасибо, что нашли время объяснить! Хотя я не использовал useMemo, я нашел способ исправить это.
Вам нужно вызвать
setPlayerCount, если вы хотите...setplayerCount