如何调度多个 action creator(React + Redux + 服务端渲染)
How to dispatch multiple action creators (React + Redux + Server-side rendering)
我一直在学习关于如何使用 React 和 Redux 构建服务器端呈现的应用程序的很棒的课程,但我现在遇到的情况是该课程没有涵盖而且我无法弄清楚我自己。
请考虑以下组件(非常基本,除了底部的导出部分):
class HomePage extends React.Component {
componentDidMount() {
this.props.fetchHomePageData();
}
handleLoadMoreClick() {
this.props.fetchNextHomePagePosts();
}
render() {
const posts = this.props.posts.homepagePosts;
const featuredProject = this.props.posts.featuredProject;
const featuredNews = this.props.posts.featuredNews;
const banner = this.props.posts.banner;
const data = ( posts && featuredProject && featuredNews && banner );
if( data == undefined ) {
return <Loading />;
}
return(
<div>
<FeaturedProject featuredProject={ featuredProject } />
<FeaturedNews featuredNews={ featuredNews } />
<Banner banner={ banner } />
<PostsList posts={ posts } heading="Recently on FotoRoom" hasSelect={ true } />
<LoadMoreBtn onClick={ this.handleLoadMoreClick.bind( this ) } />
</div>
);
}
}
function mapStateToProps( { posts } ) {
return { posts }
}
export default {
component: connect( mapStateToProps, { fetchHomePageData, fetchNextHomePagePosts } )( HomePage ),
loadData: ( { dispatch } ) => dispatch( fetchHomePageData() )
};
以上工作正常:loadData 函数发出 API 请求以获取一些数据,这些数据通过 mapStateToProps 函数馈送到组件中。但是,如果我想在同一个 loadData 函数中触发多个动作创建者怎么办?唯一可行的是如果我这样写函数:
function loadData( store ) {
store.dispatch( fetchFeaturedNews() );
return store.dispatch( fetchHomePageData() );
}
export default {
component: connect( mapStateToProps, { fetchHomePageData, fetchNextHomePagePosts } )( HomePage ),
loadData: loadData
};
但这不是很好,因为我需要对所有数据进行 returned...请记住,导出的组件最终会出现在以下路由配置中:
const Routes = [
{
...App,
routes: [
{
...HomePage, // Here it is!
path: '/',
exact: true
},
{
...LoginPage,
path: '/login'
},
{
...SinglePostPage,
path: '/:slug'
},
{
...ArchivePage,
path: '/tag/:tag'
},
]
}
];
下面是当某个路由需要组件时如何使用 loadData 函数:
app.get( '*', ( req, res ) => {
const store = createStore( req );
const fetchedAuthCookie = req.universalCookies.get( authCookie );
const promises = matchRoutes( Routes, req.path ).map( ( { route } ) => {
return route.loadData ? route.loadData( store, req.path, fetchedAuthCookie ) : null;
}).map( promise => {
if( promise ) {
return new Promise( ( resolve, reject ) => {
promise.then( resolve ).catch( resolve );
});
}
});
...
}
此外,这是动作创建者触发的动作示例。他们都return承诺:
export const fetchHomePageData = () => async ( dispatch, getState, api ) => {
const posts = await api.get( allPostsEP );
dispatch({
type: 'FETCH_POSTS_LIST',
payload: posts
});
}
和减速器:
export default ( state = {}, action ) => {
switch( action.type ) {
case 'FETCH_POSTS_LIST':
return {
...state,
homepagePosts: action.payload.data
}
default:
return state;
}
}
所以你的行为 return 一个 Promise,而你在问你怎么能 return 多个 Promise。使用 Promise.all:
function loadData({ dispatch }) {
return Promise.all([
dispatch( fetchFeaturedNews() ),
dispatch( fetchHomePageData() ),
]);
}
但是...请记住,Promise.all 将在其所有 Promise 解析时解析,并且它将 return 一个 Array 值:
function loadData({ dispatch }) {
return Promise.all([
dispatch( fetchFeaturedNews() ),
dispatch( fetchHomePageData() ),
]).then(listOfResults => {
console.log(Array.isArray(listOfResults)); // "true"
console.log(listOfResults.length); // 2
});
}
所以您可能希望以不同的方式处理它。
我一直在学习关于如何使用 React 和 Redux 构建服务器端呈现的应用程序的很棒的课程,但我现在遇到的情况是该课程没有涵盖而且我无法弄清楚我自己。
请考虑以下组件(非常基本,除了底部的导出部分):
class HomePage extends React.Component {
componentDidMount() {
this.props.fetchHomePageData();
}
handleLoadMoreClick() {
this.props.fetchNextHomePagePosts();
}
render() {
const posts = this.props.posts.homepagePosts;
const featuredProject = this.props.posts.featuredProject;
const featuredNews = this.props.posts.featuredNews;
const banner = this.props.posts.banner;
const data = ( posts && featuredProject && featuredNews && banner );
if( data == undefined ) {
return <Loading />;
}
return(
<div>
<FeaturedProject featuredProject={ featuredProject } />
<FeaturedNews featuredNews={ featuredNews } />
<Banner banner={ banner } />
<PostsList posts={ posts } heading="Recently on FotoRoom" hasSelect={ true } />
<LoadMoreBtn onClick={ this.handleLoadMoreClick.bind( this ) } />
</div>
);
}
}
function mapStateToProps( { posts } ) {
return { posts }
}
export default {
component: connect( mapStateToProps, { fetchHomePageData, fetchNextHomePagePosts } )( HomePage ),
loadData: ( { dispatch } ) => dispatch( fetchHomePageData() )
};
以上工作正常:loadData 函数发出 API 请求以获取一些数据,这些数据通过 mapStateToProps 函数馈送到组件中。但是,如果我想在同一个 loadData 函数中触发多个动作创建者怎么办?唯一可行的是如果我这样写函数:
function loadData( store ) {
store.dispatch( fetchFeaturedNews() );
return store.dispatch( fetchHomePageData() );
}
export default {
component: connect( mapStateToProps, { fetchHomePageData, fetchNextHomePagePosts } )( HomePage ),
loadData: loadData
};
但这不是很好,因为我需要对所有数据进行 returned...请记住,导出的组件最终会出现在以下路由配置中:
const Routes = [
{
...App,
routes: [
{
...HomePage, // Here it is!
path: '/',
exact: true
},
{
...LoginPage,
path: '/login'
},
{
...SinglePostPage,
path: '/:slug'
},
{
...ArchivePage,
path: '/tag/:tag'
},
]
}
];
下面是当某个路由需要组件时如何使用 loadData 函数:
app.get( '*', ( req, res ) => {
const store = createStore( req );
const fetchedAuthCookie = req.universalCookies.get( authCookie );
const promises = matchRoutes( Routes, req.path ).map( ( { route } ) => {
return route.loadData ? route.loadData( store, req.path, fetchedAuthCookie ) : null;
}).map( promise => {
if( promise ) {
return new Promise( ( resolve, reject ) => {
promise.then( resolve ).catch( resolve );
});
}
});
...
}
此外,这是动作创建者触发的动作示例。他们都return承诺:
export const fetchHomePageData = () => async ( dispatch, getState, api ) => {
const posts = await api.get( allPostsEP );
dispatch({
type: 'FETCH_POSTS_LIST',
payload: posts
});
}
和减速器:
export default ( state = {}, action ) => {
switch( action.type ) {
case 'FETCH_POSTS_LIST':
return {
...state,
homepagePosts: action.payload.data
}
default:
return state;
}
}
所以你的行为 return 一个 Promise,而你在问你怎么能 return 多个 Promise。使用 Promise.all:
function loadData({ dispatch }) {
return Promise.all([
dispatch( fetchFeaturedNews() ),
dispatch( fetchHomePageData() ),
]);
}
但是...请记住,Promise.all 将在其所有 Promise 解析时解析,并且它将 return 一个 Array 值:
function loadData({ dispatch }) {
return Promise.all([
dispatch( fetchFeaturedNews() ),
dispatch( fetchHomePageData() ),
]).then(listOfResults => {
console.log(Array.isArray(listOfResults)); // "true"
console.log(listOfResults.length); // 2
});
}
所以您可能希望以不同的方式处理它。