React Redux 中的异步 ActionCreator
Posted
技术标签:
【中文标题】React Redux 中的异步 ActionCreator【英文标题】:Asynchronous ActionCreator in React Redux 【发布时间】:2019-01-14 08:30:00 【问题描述】:我是 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
。
我现在该怎么办?抱歉发了这么长的帖子。
【问题讨论】:
您好,您可以将您的回复数据传递给您的操作payload
,然后更新您的商店。完成此操作后,您将不再需要任何 cont something
,因为它将在您的组件中以 props
的形式从 mapStateToProps
获得
我已经完成了。如您所见,我只是将 this.props.products 值分配给 something
。然而问题是,当 axios 调用结束时,something=this.props.products
已经被执行了。并且 something
被分配了主要从我的减速器设置的 initialState
值。我想确保,我的 something
变量仅分配有从 axios get 请求接收到的填充数组。
顺便说一句:可能你有错误:dispatch(productsIsLoading(false));
应该在 finally 块中,因为并不总是调用 catch。
最初我在 catch 块中有该代码。但为了简洁起见,我省略了它。
第一个问题是:你到底为什么要这个?您正在使用 React 和 Redux,因此请使用选择器的强大功能!只需在您需要时分派操作,然后让选择器将其作为组件的道具传递...然后您的渲染器将完成其余的工作,同时它是异步调用,在您的渲染器中显示一些加载反馈。那是你应该遵循的模式,请解释一下你为什么要打破这种模式。因为问题就在那里……
【参考方案1】:
我认为你已经接近得到你想要的了。首先,您应该了解 redux 操作和像 setState 这样的 react 操作是异步的,因此您必须牢记这一点来应用您的逻辑。我将在某些方面解释我的想法:
您已经在正确的位置调用了动作创建者componentDidMount,如果需要,您也可以在任何 onClick 中调用此动作。
我想,一旦您发送操作,您正在更改您的 redux 状态设置 loading true。所以现在你可以在你的渲染函数中访问这个属性,这样你就可以渲染一个加载器,直到你的 api 调用完成。
当您的 ajax 函数完成时,无论是否出错,我想您将 loading 设置为 false 并更新您的产品数据,因此您现在可以在仪表板中呈现您加载的产品。
李>您确定必须将空产品数组与接收到的数据进行比较吗?也许你可以检查你的渲染函数if (!this.props.products.length) return null
,当你加载你的页面时,你会看到一个加载器函数,然后你会看到带有产品的仪表板。
如果您确实需要将以前的产品与收到的产品进行比较,componentDidUpdate 是您的方法。在这个方法中,你可以访问你之前的 props 并与实际的 props 进行比较,小心比较数组,记住 [] === [] 是 false。也许你可以比较一下长度,比如
componentDidUpdate(prevProps)
if(prevProps.products.length !=== this.props.products.lenth)
doSomething()
只是说 componentDidUpdate 在渲染之后执行,所以要小心你的代码,不要执行额外的渲染。
希望对你有帮助,如果你不明白,请告诉我:)
【讨论】:
【参考方案2】:实际上,我希望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
);
);
如果有任何问题,请随时告诉我。
【讨论】:
以上是关于React Redux 中的异步 ActionCreator的主要内容,如果未能解决你的问题,请参考以下文章