[英]React not re-rendering after state update
我目前正在學習 React。 在我的主頁組件中,我使用掛鈎來初始化和填充 state。 我有 2 個狀態,1 個包含一個隨機口袋妖怪,另一個是 20 個隨機口袋妖怪的數組。 第一個工作正常,但不是數組。
這是主頁組件:
// Hook
import { useHomeFetch } from "../hooks/useHomeFetch";
// Image
import NoImage from '../images/missingno.png';
const Home = () => {
const { state, collection, loading, error } = useHomeFetch();
return (
<>
{ state.heroPokemon ?
<HeroImage
image={`${API.fetchSprite(state.heroPokemon)}`}
title={state.heroPokemon.name}
text='Placeholder, should include abilities, etc. to show the pokemon off.'
/>
: null}
{ collection.pokemons[0] ?
<Grid header='Popular pokemons'>
{collection.pokemons.map( pokemon => (
<h3 key={pokemon.id}>{pokemon.name}</h3>
) )}
</Grid>
: null}
</>
);
}
export default Home;
添加條件渲染后, heroPokemon 工作正常。 我的第一個想法是對集合做同樣的事情,因為它可能在所有 API 調用承諾解決之前就已經呈現了。
如果我查看反應開發工具,這就是我看到的 state:
hooks
HomeFetch
1 State : {heroPokemon: {…}}
2 State : {pokemons: Array(20)}
pokemons :
[{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
所以在我看來,調用確實完成得很好,里面有 20 個隨機的口袋妖怪對象。
這是鈎子:
const initialState = {
heroPokemon: null
}
const fetchRandomPokemons = async (ids) => {
let pokemons = [];
ids.forEach(async num => {
pokemons.push(await API.fetchPokemon(num));
});
return pokemons;
}
export const useHomeFetch = () => {
const [state, setState] = useState(initialState);
const [collection, setCollection] = useState({pokemons: []});
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const fetchPokemons = async (limit = 20) => {
try {
setError(false);
setLoading(true);
const heroPokemon = await API.fetchPokemon(randomInt(1, 898));
const randomInts = randomUniqueInt(1, 898, limit);
const pokemons = await fetchRandomPokemons(randomInts);
setState(prev => ({heroPokemon}));
setCollection(prev => ({pokemons}));
} catch (error) {
setError(true);
}
setLoading(false);
};
// Initial render
useEffect(() => {
fetchPokemons(20);
}, [])
return { state, collection, loading, error };
};
當我取出條件時, Grid
出現了,但它沒有帶有口袋妖怪名稱的 h3。 如果我 console.log 退出state
並在home
之前collection
。 最后幾個顯示正確的state.heroPokemon
和collection.pokemons
填充正確。 這讓我相信狀態已正確更新,但為什么 React 不重新渲染網格組件?
要添加,我還嘗試添加:
<p>{collection.pokemons[0]}</p>
到 home 組件,什么也沒有出現。 我覺得我可能誤解或錯過了狀態和重新渲染如何工作的關鍵部分,這導致我錯過了我可能做錯的事情。
嘗試這個:
// Hook
import { useHomeFetch } from "../hooks/useHomeFetch";
// Image
import NoImage from '../images/missingno.png';
const Home = () => {
const [newCollection, setNewCollection] =useState([])
const { state, collection, loading, error } = useHomeFetch();
useEffect(()=>{
setNewCollection(collection || []);
},[collection])
return (
<>
{ state.heroPokemon ?
<HeroImage
image={`${API.fetchSprite(state.heroPokemon)}`}
title={state.heroPokemon.name}
text='Placeholder, should include abilities, etc. to show the pokemon off.'
/>
: null}
{ newCollection.pokemons[0] ?
<Grid header='Popular pokemons'>
{newCollection.pokemons.map( pokemon => (
<h3 key={pokemon.id}>{pokemon.name}</h3>
) )}
</Grid>
: null}
</>
);
}
export default Home;
如果仍然不起作用,則分享您的回購。 所以我可以幫助你更多。 謝謝
似乎問題出在您的fetchRandomPokemons
實用程序 function 中。 即使您已經聲明fetchRandomPokemons
async
,您也不會等待任何東西。 Array.prototype.forEach
也是完全同步的。 但是,您確實將.forEach
回調聲明為async
並await
API 響應,但由於.forEach
是同步的,因此fetchRandomPokemons
function 已經返回了空的pokemons
數組並已解決。 async
關鍵字只允許 function scope 使用await
關鍵字。
const fetchRandomPokemons = async (ids) => {
let pokemons = [];
ids.forEach(async num => { // <-- synchronous
pokemons.push(await API.fetchPokemon(num));
});
return pokemons; // <-- returns []
}
...
const pokemons = await fetchRandomPokemons(randomInts); // <-- []
setCollection({ pokemons }); // <-- { pokemons: [] }
您正在記錄的是當每個API.fetchPokemon
Promise 解析時pokemons
數組發生突變的.forEach
數組。
Map 將ids
分配到 Promise 數組中,然后等待它們全部解析並返回已解析的口袋妖怪數組。
const fetchRandomPokemons = (ids) => {
return Promise.all(ids.map(API.fetchPokemon));
}
...
const fetchPokemons = async (limit = 20) => {
setError(false);
setLoading(true);
try {
const heroPokemon = await API.fetchPokemon(randomInt(1, 898));
const randomInts = randomUniqueInt(1, 898, limit);
const pokemons = await fetchRandomPokemons(randomInts);
setState({ heroPokemon });
setCollection({ pokemons });
} catch (error) {
setError(true);
}
setLoading(false);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.