我有這樣的代碼,這是Grid組件的代碼,它從LocalStorage中記錄的資訊中生成可用的騎手串列,問題是它在資訊到達之前就已經渲染了,即使在加載好之后,它也沒有重新渲染。你認為我可以用useContext來解決這個問題嗎?或者什么才是最好的解決方案?
這是一個組件:
span class="hljs-keyword">import { useEffect, useReducer, useState } from "react"/span>
import { ridersReducer } from "./hooks/ridersReducer"。
import { GridRow } from "./GridRow"/span>;
//此組件生成應用程式的網格。
export const Grid = ({ pressed, setPressed }) => {
//eslint-disable-next-line[/span]。
const [ state, dispatch ] = useReducer(ridersReducer, [] );
const [ riders, setRiders ] = useState([] );
useEffect( () => {
dispatch({
type: 'read'。
});
//With dispatch in update we update the riders。
//我們從localStorage檢索騎手的狀態。
setRiders(JSON. parse(localStorage.getItem('riders' /span>))。
}, [pressed])。
//回傳組件。
return (
<table className="table table-hover"/span>>
<thead>
<tr>/span>
<th scope="col"/span>> Horas</th>。
<th scope="col"> 自由騎手</th>
<th scope="col"> Estado</th>。
<th scope="col"/span>> Reservar</th>。
</tr>/span>
</thead>/span>
<tbody>
{
// 我們檢查騎手是否為空,并呼叫
// GridRow來生成表格的每一行
riders !== null &&(
Object.keys(riders).map( rider => (
<GridRow。
id={ riders[rider].id }
key={ riders[rider].id }
霍拉={ 騎手[騎手].霍拉 }
riders={ riders[rider].Riders }
pressed={ pressed }
setPressed={ setPressed }
dispatch={ dispatch }
/>
))
)
}
</tbody>
</table>
)
}
而這是呼叫:
import { getRiders } from "./helpers/getRiders"。
import { updateRiders } from "./helpers/updateRiders"。
export const ridersReducer = ( state, action) => {
//我們定義我們的reduce將做的不同動作。
switch(action.type){
case 'read':
localStorage.clear()。
getRiders()
.then( data => {
//span>保存狀態的騎手。
if( JSON.parse( localStorage. getItem('riders') === null ) ){
state = data.record。
} else {
state = [...JSON.parse(localStorage. getItem('riders')), data.record】。]
}
})
.then( () => {
//我們在localStorage中保存騎手的狀態,以便能夠
//從網格組件中檢索他們,并能夠顯示它。
localStorage.setItem('riders',JSON。 stringify(state))。
});
return state。
case 'update':
updateRiders()
break;
default:
return state。
};
};
uj5u.com熱心網友回復:
自定義鉤子不應該以 "use "開頭,比如 "useReducer "而不是 "ridersReducer",這樣react才知道它是一個鉤子
uj5u.com熱心網友回復:如果你想等到資料來了再渲染,只需在鉤子后面添加if條件即可
...
useEffect( ( ) => {
dispatch({
type: 'read'。
});
//With dispatch in update we update the riders。
//我們從localStorage檢索騎手的狀態。
setRiders(JSON. parse(localStorage.getItem('riders' /span>))。
}, [pressed])。
if( !riders ) return null //this will stop render null until data comes.
//回傳組件。
return
....
uj5u.com熱心網友回復:
我認為你把這個問題弄得比它需要的還要復雜。
你有來自還原器的狀態和另一個叫做riders的狀態。你不需要這兩種狀態。使用你的組件來獲取資料,然后將結果分派給你的 reducer。你的reducer應該只用這些資料來更新狀態。當狀態更新時,該組件將使用新的資料重新渲染。
如果您希望將資料添加到 localStorage,這一點也得到了簡化。您可以使用 useLocalStorage 鉤子,但是,說實話,我認為這沒有必要,但是您的使用案例并不明確。
作為一個簡化的示例:
當狀態更新時,組件將使用新的資料重新呈現。
作為一個簡化的例子:
useEffect(() =>/span> {
async function getRiders(){
const res = await fetch(url)。
const data = await res.json();
dispatch({ type: 'read', payload: data })。)
// useLocalStorage在這里或許可以,但似乎沒有必要。
});
getRiders()。
}, [pressed])。
而在你的還原器中:
function ridersReducer( state, action) {
const { type, payload } = action;
switch (action.type) {
case 'read': return payload;
default: return state。
};
然后你將迭代狀態來構建你的JS2:
>。state.map(rider => (
<GridRow()
id={rider.id}。
key={rider.id}
hora={rider.Hora}
riders={rider.Riders}>
pressed={pressed}
setPressed={setPressed}。
dispatch={dispatch}。
/>
))
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" class="snippet-box-edit snippet-box-result" frameborder="0"></iframe>
uj5u.com熱心網友回復:
這里有幾個問題:
useReducerReact鉤子的還原器應該是一個純函式,所以它不應該做任何承諾或localStorage作業,只是回傳狀態的新形狀;useEffect鉤子中發送你的API請求(API呼叫是副作用,因此鉤子的名字是這樣);useReducer回傳的更新狀態,而且根據你的代碼,你似乎根本不需要useReducer。你可能只是用useState抓住了一個騎手的串列;嘗試:
- 在
useEffect呼叫中獲取你的騎手api,當承諾解決時呼叫setRiders并將解決的騎手串列傳遞給它; - 在你的
riders串列為空時,渲染一些加載組件(你可以使用一個簡單的if陳述句來檢查riders的長度); - 渲染你的串列。
- 通過映射來渲染你的騎手串列。
如果你仍然想使用Reducer,你顯然可以,但是reduce并不是集中所有副作用的正確位置。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/334287.html
標籤:
