bounty将在4天后过期。回答此问题可获得+500声望奖励。slevin希望引起更多人对此问题的关注:请帮助一个react新手了解发生了什么
我使用react 18.2.0、redux 4.2.0和redux thunk
我希望等到调度完成,这样我就可以从服务器获取数据,并使用该数据呈现组件
我尝试在组件中执行以下操作:
import store from '../redux/store';
const featureInfoA = useSelector(featureInfo)
const featureErrorA = useSelector(featureError)
const featureStatusA = useSelector(featureStatus)
const clickFeatureFromList = (id) => {
//start dispatching
dispatch(fetchFeatureInfoById({ id, category }))
.then((e) => {
console.log('BINGO THEN ', featureInfoA, featureErrorA, featureStatusA);
})
}
//check store when a specific state changed and then get its data and render a component
store.subscribe(() => {
const state = store.getState()
if (state.features.status == 'succeeded' || state.features.status == 'failed') {
console.log('BINGO SUBSCRIBE ', featureInfoA);
accordionDetailsRootGlobal.render(<ContextInfo featureData={featureInfoA} />);
}
})
问题是,在我的控制台中,我看到:
BINGO SUBSCRIBE a
多次- 然后是存储中的
DATA from store
- 然后调用调度后
then
中的BINGO THEN a null idle
我觉得店的日志应该放在第一位
为什么我多次看到store.subscribe
内的“BINGO SUBSCRIBE a”?
为什么我从来没有看到来自服务器的最终数据?“BINGO THEN a null idle”包含初始状态,即使“DATA from store”返回了数据。
顺便说一句,这是我的店,功能
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
const FEATURE_URL = 'http://localhost:3500/map'
//status : idle, loading, succeeded, failed
const initialState = {
info:'a',
status:'idle',
error:null
}
export const fetchFeatureInfoById = createAsyncThunk('feature/fetchInfoById', (originalData) => {
console.log('fetchFeatureInfoById originalData ', originalData);
fetch(FEATURE_URL + '/feature/' + originalData.id + '/' + originalData.category)
.then((response) => response.json())
.then((data) => {
console.log('DATA from store ', data);
return data;
})
.catch((error) => {
return error.message;
});
})
export const featuresSlice = createSlice({
name: 'features',
initialState,
reducers: {
featureInfoById: {
reducer(state, action) {
//do something with the id
console.log('feature state ', ' -- state : ',state.status, ' -- action : ', action);
},
prepare(category, id) {
return{
payload:{
category,
id
}
}
}
}
},
extraReducers(builder) {
builder
.addCase(fetchFeatureInfoById.pending, (state, action) => {
state.status = 'loading'
})
.addCase(fetchFeatureInfoById.rejected, (state, action) => {
state.status = 'failed'
state.error = action.error.message
})
.addCase(fetchFeatureInfoById.fulfilled, (state, action) => {
console.log('fulfilled data store ', state, action);
state.status = 'succeeded'
state.info = action.palyload
})
}
})
export const featureInfo = (state) => state.features.info;
export const featureError = (state) => state.features.error;
export const featureStatus = (state) => state.features.status;
export const {featureInfoById} = featuresSlice.actions
export default featuresSlice.reducer
我只想在调度完成后得到数据,用它们来呈现一个组件。请帮助我了解我做错了什么,以及如何修复。
2条答案
按热度按时间ztyzrc3y1#
你不需要做
store.subscribe
的事情。选择器应该更新,并且它将导致组件的呈现。因此,最初featureInfoA是未定义的,但是在承诺解决之后,它将更新存储,这将触发组件中的呈现
ctehm74n2#
为什么我看到"宾果SUBSCRIBE a"是在商店里。订阅多次?
这是因为正如医生所说
添加更改侦听器。每当调度操作时都会调用该侦听器,并且状态树的某些部分可能已更改。
因此,基本上,每次调度任何操作,并且状态树的任何部分可能已被更改,它都会被触发。这指的是整个存储(不仅仅是
featuresSlice
)为什么我从来没有看到来自服务器的最终数据?"BINGO THEN a null idle"包含初始状态,即使"DATA from store"返回了数据。
这很可能是因为
fetchFeatureInfoById
没有返回任何东西(请注意,return data;
部分在回调函数中,但main函数没有返回任何东西),所以在额外的reducer中action.payload
没有值。因此,为了能够正确地设置切片额外缩减器的切片状态,您需要做的是从
fetchFeatureInfoById
函数返回获取结果,因此,基本上您的函数看起来如下所示:PS:没有一个可复制的例子不是100%这将修复你所有的问题,但它至少应该为你指明正确的方向。
额外建议(与其他答案相关):
我认为你至少可以使用一个useEffect?只在
accordionDetailsRootGlobal
改变或featureInfoA
时触发一个效果会更有效(所以基本上有一个useEffect与这2个依赖项,并在这2个改变之一时渲染ContextInfo
,而不是在每次商店更新时渲染)。