React/Redux 状态在第二次操作调用时为空

Posted

技术标签:

【中文标题】React/Redux 状态在第二次操作调用时为空【英文标题】:React/Redux State is empty on second action call 【发布时间】:2016-08-14 07:04:03 【问题描述】:

我对 React/Redux 还比较陌生,所以如果这是一个简单的问题,我深表歉意,但我还没有找到解决方案。

我有两个动作:

// DESTINATIONS
// ==============================================

export const DESTINATION_REQUEST = 'DESTINATION_REQUEST';
export const DESTINATION_SUCCESS = 'DESTINATION_SUCCESS';
export const DESTINATION_FAILURE = 'DESTINATION_FAILURE';

export function loadDestination (params, query) 

    const state = params.state ? `/$params.state` : '';
    const region = params.region ? `/$params.region` : '';
    const area = params.area ? `/$params.area` : '';

    return (dispatch) => 
        return api('location', url: `/accommodation$state$region$area`).then((response) => 
            const destination = formatDestinationData(response);

            dispatch(
                type: DESTINATION_SUCCESS,
                destination
            );
        );
    ;






// PROPERTIES
// ==============================================

export const PROPERTIES_REQUEST = 'PROPERTIES_REQUEST';
export const PROPERTIES_SUCCESS = 'PROPERTIES_SUCCESS';
export const PROPERTIES_FAILURE = 'PROPERTIES_FAILURE';

export function loadProperties (params, query, rows = 24) 

    return (dispatch, getState) => 

        console.log(getState());

        return api('search', locationId: xxxxxx, rows: rows).then((response) => 
            const properties = response.results.map(formatPropertiesData);

            dispatch(
                type: PROPERTIES_SUCCESS,
                properties
            );
        );
    ;

这些与它们的相对化简器相结合:

// DESTINATIONS REDUCERS
// ==============================================

export default function destination (state = [], action) 
    switch (action.type) 
    case DESTINATION_SUCCESS:
        return action.destination;
    default:
        return state;
    






// PROPERTIES REDUCERS
// ==============================================

export default function properties (state = [], action) 
    switch (action.type) 
    case PROPERTIES_SUCCESS:
        return action.properties;
    default:
        return state;
    

并且它们在组件内被调用(connectDataFetchers 循环调用被调用的动作并将它们返回给组件以进行服务器端渲染):

// PROPTYPES
// ==============================================

Search.propTypes = 
    destination: PropTypes.object.isRequired,
    properties: PropTypes.array.isRequired
;





// ACTIONS
// ==============================================

function mapStateToProps (destination, properties) 
    return destination, properties;






// CONNECT & EXPORT
// ==============================================

export default connect(mapStateToProps)(
    connectDataFetchers(Search, [loadDestination, loadProperties])
);

export default function connectDataFetchers (Component, actionCreators) 
    return class DataFetchersWrapper extends React.Component 
        static propTypes = 
            dispatch: React.PropTypes.func.isRequired,
            location: React.PropTypes.object.isRequired,
            params: React.PropTypes.object.isRequired
        ;
        
        static fetchData (dispatch, params = , query = ) 
            return Promise.all(
                actionCreators.map((actionCreator) => dispatch(actionCreator(params, query)))
            );
        

        componentDidMount () 
            DataFetchersWrapper.fetchData(
                this.props.dispatch,
                this.props.params,
                this.props.location.query
            );
        

        render () 
            return (
                <Component ...this.props />
            );
        
    ;

我需要运行第一个操作 (loadDestination),它将返回一个 ID,然后需要传递给第二个操作以加载具有该位置 ID 的属性。

如果我对 locationID 进行硬编码,这可以正常工作,但如果我尝试通过getState() 访问loadProperties 中的状态,那么它会返回 destination: [], properties: []

有没有办法通过状态访问第一个操作的值?

解决方案

按照@pierrepinard_2 的建议,设法让它工作

我创建了一个新动作,它按我需要的顺序调度其他两个动作:

// SEARCH
// ==============================================

export function loadSearch (params, query) 
    
    return (dispatch) => 
        return dispatch(
            loadDestination(params, query)
        ).then(() => 
            return dispatch(
                loadProperties(params, query)
            )
        )
    


// DESTINATIONS
// ==============================================

export const DESTINATION_REQUEST = 'DESTINATION_REQUEST';
export const DESTINATION_SUCCESS = 'DESTINATION_SUCCESS';
export const DESTINATION_FAILURE = 'DESTINATION_FAILURE';

export function loadDestination (params, query) 

    const state = params.state ? `/$params.state` : '';
    const region = params.region ? `/$params.region` : '';
    const area = params.area ? `/$params.area` : '';

    return (dispatch) => 
        return api('location', url: `/accommodation$state$region$area`).then((response) => 
            const destination = formatDestinationData(response);
            
            dispatch(
                type: DESTINATION_SUCCESS,
                destination
            );
        );
    ;

  
  // PROPERTIES
// ==============================================

export const PROPERTIES_REQUEST = 'PROPERTIES_REQUEST';
export const PROPERTIES_SUCCESS = 'PROPERTIES_SUCCESS';
export const PROPERTIES_FAILURE = 'PROPERTIES_FAILURE';

export function loadProperties (params, query, rows = 24) 

    return (dispatch, getState) => 
        return api('search', locationId: getState().destination.id, rows: rows).then((response) => 
            const properties = response.results.map(formatPropertiesData);

            dispatch(
                type: PROPERTIES_SUCCESS,
                properties
            );
        );
    ;

然后在组件中我只请求一个动作:

export default connect(mapStateToProps)(
    connectDataFetchers(Search, [loadSearch])
);

【问题讨论】:

您能分享一下 是如何调用 loadDestination 和 loadProperties 的吗? @DamienLeroux - 我从搜索组件和connectDataFetchers 函数中添加了更多代码 【参考方案1】:

您在 fetchData() 方法中使用 Promise.all():您的操作是并行调度的,而不是一个接一个。

为确保调用第一个目标然后调用属性,您应该为您的搜索组件创建一个特定的异步操作创建器。在这种情况下,此异步操作创建器将实现您需要的连续请求。

【讨论】:

我尝试过最初在一个单独的函数中调用这两个函数,但没有附加到 mapStateToProps 中的各个变量。我该如何维持这种关系? 我不明白你的意思。 mapStateToProps() 函数从您的应用程序的唯一状态中检索您的道具。接收api请求的顺序有问题吗?如果您使用 redux-thunk 中间件来处理您的异步请求并希望将 dispatch() 调用与 then() 链接起来,请确保始终在您的异步操作创建者中返回承诺(github.com/gaearon/redux-thunk#composition 中的更多信息)。例如,你应该“return dispatch(...);”在您的动作创建者中。 感谢@pierrepinard_2 - 按照 redux-thunk 的建议,我得到了这个工作并添加了上面的解决方案【参考方案2】:

我同意@pierrepinard_2。

使用 bluebird 中的 promise.map,您应该能够同步调用所有给定的 Promise。

这个post on stack overflow 应该可以帮助你解决这个问题。

让我们知道它是否有效

【讨论】:

以上是关于React/Redux 状态在第二次操作调用时为空的主要内容,如果未能解决你的问题,请参考以下文章

React Redux 状态在页面刷新时丢失

从另一个活动调用时为空侦听器

Ext JS第二次加载时为空ItemSelector

React Redux 问题传递状态值

首次提交表单时为空值

ClaimRequirementFilter - TypeFilterAttribute处理