Javascript 带Redux的异步操作
我有一个连接到Redux商店的React组件。我在Javascript 带Redux的异步操作,javascript,reactjs,redux,Javascript,Reactjs,Redux,我有一个连接到Redux商店的React组件。我在组件willmount生命周期方法中获取资源(帖子) componentWillMount() { this.props.fetchPosts(); } 组件将订阅Redux store并从该store获取isFetching和posts const mapStateToProps = (state) => { return { posts: getAllPosts(state), isFetching: getI
组件willmount
生命周期方法中获取资源(帖子)
componentWillMount() {
this.props.fetchPosts();
}
组件将订阅Redux store并从该store获取isFetching
和posts
const mapStateToProps = (state) => {
return {
posts: getAllPosts(state),
isFetching: getIsFetchingPosts(state),
}
}
我想在微调器仍在抓取时显示它,因此在render
方法中我想这样做
render() {
if (this.props.isFetching) {
return <Spinner />
}
return this.props.posts.map(post => <PostItem key={post.id}{...post}/>)
}
提前谢谢你 简单的回答是,考虑到您的实现,这是预期的行为。您正在将
isFetching
状态映射到一个道具。下面是正在发生的事情:
isFetching
的初始值为false
,因此isFetching
属性值为false
,因此呈现为false
isFetching
更改为true
。此新状态映射到一个新的isFetching
prop值true
,该值会导致重新渲染,并在其中渲染为true
isFetching
更改回false
。与(2)中相同,这会导致重新渲染,isFetching
为false
true,false
*,那么简单的解决方案是在还原程序的初始状态下将isFetching
设置为true
对于这个组件来说,这个实现在设计层面上是否有意义是一个更广泛的问题,这里没有足够的上下文来回答:-)
*update为了完整起见,我应该说我不知道render()
函数是否会被调用两次,在这种情况下,isFetching
解析为true,false
,或者调用true,true,false
三次。我怀疑react-redux可能会优化组件的渲染,这样,如果映射的正在获取属性从true
->true
更改,则不会发生重新渲染,但我不确定这一点-如果您能让我知道您的日志输出,我将不胜感激并感兴趣
在任何情况下,由于标准的react virtual DOM diffing优化,在DOM级别上肯定只会发生两次渲染,因此实际上结果是相同的不太清楚fetchPosts是什么,您不在MapStateTops中提供它。来自state的post和fetchPosts之间的连接是什么(函数是否更新state?)。你能澄清一下吗?在开始时使用isFetching=false
是一个不错的行为,因为这只意味着操作还没有到达减速机,ierender
是在fetchPosts
将标志设置为true之前调用的。谢谢你的回答!我刚刚更新了问题。“理想情况下,当此容器第一次呈现时,isFetching state已设置为true并显示微调器。我需要进行哪些更改才能实现此目的?”您对此有何想法?顺便说一句,我正在使用反应路由器。没问题。老实说,这是我在自己的减速器设计中一直在努力解决的问题——如何保持初始状态,并为组件的每个新渲染重置该初始状态。您可以设置初始状态,使isFetching
为true,然后在后续渲染此组件之前,确保在状态树中将其重置为true
。这可能有点费力,取决于您的设计。另一个更简单的方法是保持isFetching
作为组件的内部状态,每次使用getInitialState()安装组件时重置它(cont)。我认为这确实是没有明确答案的设计选择之一。这取决于你的应用程序:-)对于我来说,正如我所说的,在使用redux编写应用程序时,将这些小的、自包含的UI状态保存在哪里是一个大的开放问题。
/*** Action Creator ***/
export const fetchPosts = () => (dispatch) => {
dispatch({
type: REQUEST_POSTS,
});
return axios({
method: 'get',
url: `${API_URL}/posts`,
})
.then(({data}) => {
dispatch({
type: RECEIVE_POSTS,
payload: data.posts,
})
})
.catch((response) => {
// some error handling.
});
}
/*** Reducers ***/
const initialState = {
isFetching: false,
allIds: [],
byId: {},
};
const isFetching = (state = initialState.isFetcthing, action) => {
switch (action.type) {
case REQUEST_POSTS:
return true;
case RECEIVE_POSTS:
return false;
default:
return state;
}
}
const allIds = (state = initialState.allIds, action) => {
switch (action.type) {
case RECEIVE_POSTS:
return action.payload.map(post => post.id);
default:
return state;
}
}
const byId = (state = initialState.byId, action) => {
switch (action.type) {
case RECEIVE_POSTS:
return action.payload.reduce((nextState, post) => {
nextState[post.id] = post;
return nextState;
}, {...state});
default:
return state;
}
}
const posts = combineReducers({
isFetching,
allIds,
byId,
});
export default posts;
/*** Selectors in 'posts.js' file ***/
export const getAllPosts = (state) => {
const { allId, byId } = state;
return allIds.map(id => byId[id]);
}
/*** rootReducer file ***/
import posts, * as fromPosts from './posts';
const rootReducer = combineReducers({
posts,
})
export default rootReducer;
export const getAllPosts = (state) => {
return fromPosts.getAllPosts(state.posts);
};