React-native 和 Redux 健康的方式来调用 props 更改的操作
Posted
技术标签:
【中文标题】React-native 和 Redux 健康的方式来调用 props 更改的操作【英文标题】:React-native and Redux healthy way to call actions on props change 【发布时间】:2019-03-07 23:17:53 【问题描述】:我一直在使用 react-native 和 redux 有一段时间了,当道具发生变化时我学会调用动作的方式是使用 componentWillReceiveProps,但是当我使用它时,我需要在 if 和有时它之间传递如果出错了,那么我需要添加更多的东西来防止它。
这是我做过的一个例子。我知道这不是最好的方法,但这是我能想到的。
componentWillReceiveProps(newProps)
if(Object.keys(newProps.selected_product).length > 0)
if(Object.keys(this.props.current_location).length > 0 || Object.keys(newProps.current_location).length > 0)
this._handleNextPage(2);
this.props.verifyProductById(newProps.selected_product, newProps.current_location, this.props.token);
else
this.props.statusScanner(false);
this._handleNextPage(1);
else if(Object.keys(newProps.historic_product_confirm).length > 0)
if(newProps.historic_product_confirm.location._id == newProps.current_location._id)
this.props.handleModalConfirmPrice(!this.props.modal_confirmPrice_status)
else if(newProps.scanResult != "")
this.props.statusScanner(false);
if(Object.keys(newProps.current_location).length > 0)
this._handleNextPage(2);
else
this._handleNextPage(1);
else
this._handleNextPage(0);
我需要的是一种在道具发生变化时调用我的动作的健康方式。
编辑: 这里我有完整的 OfferScene 和一个动作文件示例:
优惠场景: https://gist.github.com/macanhajc/0ac98bbd2974d2f6fac96d9e30fd0642
UtilityAction: https://gist.github.com/macanhajc/f10960a8254b7659457f8a09c848c8cf
【问题讨论】:
您必须具有导致这些属性发生变化的操作,例如 selected_product、history_product_confirm、scanResult 等。您可以将逻辑从操作发送的位置放置,例如用户操作或 API 结果。但是当您的应用程序/组件扩展时,上面指定的代码会很混乱。 尽量将问题分解为多个组件,这将有助于编写更清晰和可扩展的代码。 您能否发布您的示例actions
或您如何处理 api?
@Goldy 我已经这样做了,但在这种情况下,代码来自场景,我需要更改 currentPage 以在组件之间导航,并且由滚动视图控制。
@PritishVaidya 我现在已经发布了完整的场景和动作文件。
【参考方案1】:
正如另一个答案中提到的,componentWillReceiveProps
正在被逐步淘汰,所以我的目标是尽可能消除它。您将对代码进行面向未来的验证,并使您的组件逻辑更具声明性和易于推理。作为一个对像这样的生命周期方法滥用负责(并为此感到沮丧)的人,这里有一些对我有帮助的事情。
请记住,当使用redux-thunk
时,除了将dispatch
作为第一个参数传递之外,您还可以将getState
作为第二个参数传递。这允许您访问动作逻辑中的状态值,而不是将它们带入组件的 props 并添加混乱。比如:
export const ExampleAction = update =>
(dispatch, getState) =>
const exampleBool = getState().ExampleReducer
if (exampleBool)
dispatch(
type: 'UPDATE_EXAMPLE_STATE',
update
)
当您的操作依赖于从 API 调用获取的结果时,在操作逻辑中使用 async/await 可以成为救命稻草:
export const ExampleAction = () =>
async (dispatch, getState) =>
const valueToCheck = getState().ExampleReducer
, result = await someAPICall(valueToCheck)
.catch(e => console.log(e))
if (result.length > 0)
dispatch(
type: 'UPDATE_EXAMPLE_STATE',
update: result
)
对于组件的渲染行为在状态更新后取决于某些状态值的情况,我强烈推荐reselect。一个非常基本的例子是这样的:
component.js
import React, Component, Fragment from 'react'
import connect from 'react-redux'
import shouldDisplayItems from '../selectors'
import MyListviewComponent from './myListview'
class ItemList extends Component
render()
const shouldDisplayItems, items = this.props
return (
<>
shouldDisplayItems && <MyListviewComponent items=items />
</>
)
const mapStateToProps = ( ListItems ) => shouldDisplayItems(ListItems)
export default connect(mapStateToProps)(ItemList)
selectors.js:
(假设您的 ListItems 减速器具有参数 items
和 visibilityFilter
)
import createSelector from 'reselect'
export const shouldDisplayItems = createSelector(
[state => state],
( items, visibilityFilter ) =>
return
shouldDisplayItems: visibilityFilter && items.length > 0,
items
)
我应该提到另一个选择是使用higher-order components,但是在很好地掌握如何将过多的命令式逻辑排除在组件之外之前使用这种方法可能会很棘手(我很难学会这一点) .
【讨论】:
【参考方案2】:我同意@AnuragChutani 和@Goldy 的代码清晰性;将其分解为更多的组件或功能。
现在,在对您的 componentWillReceiveProps 函数进行了一些审查之后,它肯定不够具体,无法准确缩小哪些 prop 更改的范围。如果任何连接的 redux 变量发生变化,则每次都会调用 componentWillReceiveProps 函数。
例如如果 'token' 或 'selected_product' 更新,componentWillReceiveProps 将被触发,即使您不希望它触发令牌更新。
您可以对 props 中的特定变量更新使用比较。 例如使用 lodash
if(!_.isEqual( nextProps.selected_product, this.props.selected_product ))
// if props are different/updated, do something
其次,您可以在操作中调用操作/回调来缩小导航范围。 例如
takePicture = (camera, options)
...
//on success
dispatch(handleModalConfirmPrice())
...
【讨论】:
以上是关于React-native 和 Redux 健康的方式来调用 props 更改的操作的主要内容,如果未能解决你的问题,请参考以下文章
React-native + Redux(Combine Reducers):创建状态结构
Redux 和 React-Native:无法读取未定义的属性“类型”
路由器状态没有通过 redux 保持在 react-native