React Redux中的异步ActionCreator

时间:2018-08-07 09:38:32

标签: javascript reactjs redux react-redux redux-thunk

我在React-Redux中还很陌生。正在处理一个应用程序。事实是,我可能在异步执行Redux actionCreator时遇到了一些问题。

下面是我的组件。假设我想从componentDidMount()或onclick事件监听器中调用actionCreator。

class Dashboard extends PureComponent {

     componentDidMount() {

          this.props.getProductsAndPackages();

          let something = [];
          something = this.props.products;

     }
....................................
}

或者,函数this.props.getProductsAndPackages();可以是执行相同操作,上下文相同的onClick事件处理程序。首先解释我的代码后,我会问我的问题。

在“信息中心”容器的下方:

Dashboard.propTypes = {
getProductsAndPackages: PropTypes.func.isRequired,
products: PropTypes.array.isRequired,
.......................

 };

const mapStateToProps = (state) => {
    return {
         .....................
         products: state.products.products,
         ...................
    };  
};


const mapDispatchToProps = (dispatch) => {
    return {
        getProductsAndPackages: () => dispatch(getProductsAndPackagesActionCreator()),
    };
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Dashboard));

我的actionCreator如下:

export const getProductsAndPackagesActionCreator = () => {

return (dispatch) => {

    dispatch(productsIsLoading(true));

    let url = 'xyz';

    if(!!localStorage.getItem('_token')) {
        const local_token = localStorage.getItem('_token');
        const fullToken = 'Bearer '.concat(local_token);

        axios.get(url, {headers: {Authorization: fullToken}})
            .then(response => {
                dispatch(productsIsLoading(false));
                if (response.data.statusCode === 200) {
                    dispatch(productsFetched(true));
                    dispatch(products(response.data.data));
                } else {
                    dispatch(productsFetched(false));
                    dispatch(productsErrors(response.data.message));
                }

            })
            .catch(error => {


            });

    } else {

        axios.get(url)
            .then(response => {
                dispatch(productsIsLoading(false));
                if (response.data.statusCode === 200) {
                    dispatch(productsFetched(true));
                    dispatch(products(response.data.data));
                } else {
                    dispatch(productsFetched(false));
                    dispatch(productsErrors(response.data.message));
                }

            })
            .catch(error => {
                console.log(error);
                dispatch(productsIsLoading(false));
                dispatch(productsErrors(error.message));

            });

    }


};
};

现在,我希望我的getProductsAndPackagesActionCreator()返回一个Promise或允许我的something变量获取从服务器返回的实际数据的任何内容。现在,到我获取实际数据时,行something=this.props.products已被执行,并且我返回了为products设置的initialValue。

我知道,每当收到填充的products时,组件都会重新呈现,但这对我的决策没有帮助。

顺便说一下,我正在使用redux-thunk

我现在该怎么办?抱歉,这么长的帖子。

2 个答案:

答案 0 :(得分:1)

实际上,我实际上希望getProductsAndPackagesActionCreator()退还一个诺言,说实话,这很简单。我发现,如果您只是return axios.get()axios.post(),它将返回一个承诺。因此,修改后的代码如下所示:

export const getProductsAndPackagesActionCreator = () => {

  return (dispatch) => {

    dispatch(productsIsLoading(true));

    let url = 'xyz';

    if(!!localStorage.getItem('_token')) {

        return axios.get(url, {headers: {Authorization: fullToken}})
            .then(response => {
               ............
               ............
            })
            .catch(error => {


            });

    } else {

        return axios.get(url)
            .then(response => {
                ...........
                ...........
            })
            .catch(error => {
                console.log(error);
            });
    }
  };
};

然后,我可以在componentDidMount()或任何onClick事件中执行以下操作:

this.props.getProductsAndPackages().then(() => {
    this.setState({
        ...this.state,
        clicked_product: this.props.product_by_id
    }, () => {

       //do other stuffs

    });
});

请随时告诉我是否有问题。

答案 1 :(得分:0)

我认为您即将获得想要的东西。首先,您应该了解redux动作和诸如setState之类的反应动作是异步的,因此必须牢记这一点来应用逻辑。我将在某些方面解释我的想法:

  1. 您已在正确的位置 componentDidMount 处调用了操作创建者,也可以根据需要在任何onClick中调用此操作。

  2. 我猜想,一旦您调度动作,就将更改redux状态设置为true。因此,现在您可以在render函数中访问此属性,以便可以渲染Loader直到api调用完成。

  3. 当您的ajax函数完成时(无论是否出现错误),我想您是将loading设置为false并更新产品数据,以便现在就可以在仪表板中呈现已加载的产品。

您确定必须将空产品数组与接收到的数据进行比较吗?也许您可以签入渲染功能if (!this.props.products.length) return null,当您加载页面时,您将看到一个加载器功能,随后将看到带有产品的仪表板。

如果您确实需要将以前的产品与收到的产品进行比较,请使用 componentDidUpdate 。在此方法中,您可以访问以前的道具并与实际道具进行比较,请谨慎比较数组,请记住[] === []为假。也许您可以比较长度,例如

componentDidUpdate(prevProps){
   if(prevProps.products.length !=== this.props.products.lenth){          
       doSomething()
   }
}

只是说componentDidUpdate是在渲染之后执行的,因此请谨慎使用代码,以免执行额外的渲染。

希望这会有所帮助,如果您不明白,请告诉我:)