业务逻辑放在redux的什么地方?行动或商店
Where to put business logic in redux? action or store
我从 Reflux 到 Redux。在 Reflux 中,你的业务逻辑只存在于商店中,但在 Redux 中它似乎不同..例如在“Redux”中我有 "async-action" 我用“redux-thunk”实现了它。
在一种情况下,我想检查我的操作中的某些内容,如果需要,我会向服务器发送请求并获取一些数据。在这种情况下,我必须检查我的操作逻辑,实际上我的业务逻辑存在于操作中并存储在一起,但它不好..你的解决方案是什么?
例如,我有复选框,我检查了一些条件,如果结果为真,我向服务器发送请求,这是我的操作代码,正如你所看到的,我的业务逻辑在我的操作和 Reducer 上:
export function onCheckboxClick({itemId}) {
return (dispatch, getState) => {
let state = getState().get('myReducer');
let myConditionResult = state.get('foods').get(0).get('test');//for exmaple check some condition in my store
dispatch({type: 'CHECKBOX_CLICK', itemId});// for change the checkbox checked
if (myConditionResult) {
myApi.deleteOrderItem({itemId}).then(()=> {
dispatch({type: 'DELETE_ORDER_ITEM_FULFILLED', itemId});
}).catch((err)=> {
console.log(err);
dispatch({type: 'DELETE_ORDER_ITEM_REJECTED', itemId});
});
}
};
}
提前致谢
引用Redux FAQ entry on "how to split business logic between action creators and reducers":
There's no single clear answer to exactly what pieces of logic should go in a reducer or an action creator.
If you put all the logic in the action creator, you end up with fat action objects that declare the updates to the state. Reducers become pure, dumb, add-this, remove that, update these functions. They will be easy to compose. But not much of your business logic will be there. If you put more logic in the reducer, you end up with nice, thin action objects, most of your data logic in one place, but your reducers are harder to compose since you might need info from other branches. You end up with large reducers or reducers that take additional arguments from higher up in the state.
分派一个被减速器忽略的动作是有效的,首先检查状态并决定不分派一个动作也是有效的。最终,它确实归结为您喜欢什么。
如前所述,根据您的用例,有多种方法可以执行此操作。我能做的是根据推测您的用例列出您似乎更合适的内容。
1.组件内部的逻辑。
通过使用 react-redux
中的 connect
将状态映射到道具,可以将保持条件的状态引入组件
您还将动作导入此组件文件并将动作映射到道具。
下面的示例演示了如何将状态和动作引入组件文件。你如何使用它取决于你。我把它放在一个简单的上下文中。因此,您可以在希望执行逻辑的位置调用 myFunction()
。
MyComponent.js
import React, { Component} from 'react'
import { connect } from 'react-redux'
import { onCheckboxClick } from 'path/to/action'
class MyComponent extends Component {
myFunction() {
const { theConditiion, onCheckboxClick } = this.props
if (theConditiion) {
onCheckboxClick({itemId: 'someItemid'})
}
}
render() {
//...
}
}
const mapStateToProps = (state) => ({
theCondition: state.wherever.the.data.lives.in.store
})
export default connect(
mapStateToProps,
{ onCheckboxClick }
)(MyComponent)
因此,对于上面的示例,您可以删除当前在 onCheckboxClick 函数中的条件检查。
2。将逻辑放入中间件。
下面的示例演示了如何分派操作,但首先,'catching' 特定类型的操作,假设条件为真,您可以进行 api 调用,然后dispatch further actions,如果为 false,则将 action 传递给下一个中间件。
myMiddleware.js
const onCheckboxClick = store => next => action => {
if (action.type == 'CHECKBOX_CLICK') {
let theConditiion = store.getState().wherever.the.data.lives.in.store
if (theConditiion) {
// 1. make the api call here, or,
// 2. dispatch an action specific to handling api calls.
// E.g. Create another middleware to catch action type `API_CALL`
// This middleware can then handle all api calls, and dispatch actions for api requests, responses and errors.
const newAction = {...action, type: 'API_CALL' }
store.dispatch(newAction)
// When you use store.dispatch(), the action will be passed back to the top of the middleware chain.
}
return next(action) // this will pass the action to the next middleware in the chain.
}
export default onCheckboxClick
这是一个广泛的概述,可帮助您思考最有效的方法。请记住,随着您的应用程序的开发,您会注意到重复的逻辑可以在哪些地方成为它自己的功能。
这是一些与 redux 推荐相违背的固执己见的答案。
TL;DR 都不是
更长的答案:在所谓的异步操作中从中间件调用。在 redux 社区中,它被称为 "thunk" 或 "saga".
首先,一些定义:
- action: 普通对象
{ type: 'ACTION_TYPE', payload: { data } }
- action creator: returns action.
的函数
- async action: 从middleware.
调用的函数
- async action creator: returns async action
的函数
- 中间件: 一个可以处理所有动作,调度其他动作并可以访问存储状态的函数。
那么,我们从哪里调用业务逻辑呢?
如果仔细观察,您会发现我们不需要 async action 和 async action creator。我们可以有一个简单的 action 直接在 middleware.
中处理
在 middleware 中,我们可以为每个 action 提供专用的 handler。这个 handler 的行为类似于 async action 但我们不这么称呼它。我们称它为 interactor.
所以一个新的定义:
interactor:本质上是 redux 中 async action 的抽象,但不是特定于 redux 的。 Interactor 获取数据、调用业务逻辑并发送结果 "actions".
middleware = (...) => {
// if(action.type == 'HIGH_LEVEL')
interactors[action.name]({ dispatch, params: action.payload })
}
const interactors = {
async highLevelAction({ dispatch, params }) {
dispatch({ loading: true });
const data = await api.getData(params.someId);
const processed = myPureLogic(data);
dispatch({ loading: false, data: processed });
}
}
发货方式:
dispatch({ type: 'HIGH_LEVEL', name: 'highLevelAction', { someId: 1 } })
我从 Reflux 到 Redux。在 Reflux 中,你的业务逻辑只存在于商店中,但在 Redux 中它似乎不同..例如在“Redux”中我有 "async-action" 我用“redux-thunk”实现了它。
在一种情况下,我想检查我的操作中的某些内容,如果需要,我会向服务器发送请求并获取一些数据。在这种情况下,我必须检查我的操作逻辑,实际上我的业务逻辑存在于操作中并存储在一起,但它不好..你的解决方案是什么?
例如,我有复选框,我检查了一些条件,如果结果为真,我向服务器发送请求,这是我的操作代码,正如你所看到的,我的业务逻辑在我的操作和 Reducer 上:
export function onCheckboxClick({itemId}) {
return (dispatch, getState) => {
let state = getState().get('myReducer');
let myConditionResult = state.get('foods').get(0).get('test');//for exmaple check some condition in my store
dispatch({type: 'CHECKBOX_CLICK', itemId});// for change the checkbox checked
if (myConditionResult) {
myApi.deleteOrderItem({itemId}).then(()=> {
dispatch({type: 'DELETE_ORDER_ITEM_FULFILLED', itemId});
}).catch((err)=> {
console.log(err);
dispatch({type: 'DELETE_ORDER_ITEM_REJECTED', itemId});
});
}
};
}
提前致谢
引用Redux FAQ entry on "how to split business logic between action creators and reducers":
There's no single clear answer to exactly what pieces of logic should go in a reducer or an action creator.
If you put all the logic in the action creator, you end up with fat action objects that declare the updates to the state. Reducers become pure, dumb, add-this, remove that, update these functions. They will be easy to compose. But not much of your business logic will be there. If you put more logic in the reducer, you end up with nice, thin action objects, most of your data logic in one place, but your reducers are harder to compose since you might need info from other branches. You end up with large reducers or reducers that take additional arguments from higher up in the state.
分派一个被减速器忽略的动作是有效的,首先检查状态并决定不分派一个动作也是有效的。最终,它确实归结为您喜欢什么。
如前所述,根据您的用例,有多种方法可以执行此操作。我能做的是根据推测您的用例列出您似乎更合适的内容。
1.组件内部的逻辑。
通过使用 react-redux
中的connect
将状态映射到道具,可以将保持条件的状态引入组件
您还将动作导入此组件文件并将动作映射到道具。
下面的示例演示了如何将状态和动作引入组件文件。你如何使用它取决于你。我把它放在一个简单的上下文中。因此,您可以在希望执行逻辑的位置调用 myFunction()
。
MyComponent.js
import React, { Component} from 'react'
import { connect } from 'react-redux'
import { onCheckboxClick } from 'path/to/action'
class MyComponent extends Component {
myFunction() {
const { theConditiion, onCheckboxClick } = this.props
if (theConditiion) {
onCheckboxClick({itemId: 'someItemid'})
}
}
render() {
//...
}
}
const mapStateToProps = (state) => ({
theCondition: state.wherever.the.data.lives.in.store
})
export default connect(
mapStateToProps,
{ onCheckboxClick }
)(MyComponent)
因此,对于上面的示例,您可以删除当前在 onCheckboxClick 函数中的条件检查。
2。将逻辑放入中间件。
下面的示例演示了如何分派操作,但首先,'catching' 特定类型的操作,假设条件为真,您可以进行 api 调用,然后dispatch further actions,如果为 false,则将 action 传递给下一个中间件。
myMiddleware.js
const onCheckboxClick = store => next => action => {
if (action.type == 'CHECKBOX_CLICK') {
let theConditiion = store.getState().wherever.the.data.lives.in.store
if (theConditiion) {
// 1. make the api call here, or,
// 2. dispatch an action specific to handling api calls.
// E.g. Create another middleware to catch action type `API_CALL`
// This middleware can then handle all api calls, and dispatch actions for api requests, responses and errors.
const newAction = {...action, type: 'API_CALL' }
store.dispatch(newAction)
// When you use store.dispatch(), the action will be passed back to the top of the middleware chain.
}
return next(action) // this will pass the action to the next middleware in the chain.
}
export default onCheckboxClick
这是一个广泛的概述,可帮助您思考最有效的方法。请记住,随着您的应用程序的开发,您会注意到重复的逻辑可以在哪些地方成为它自己的功能。
这是一些与 redux 推荐相违背的固执己见的答案。
TL;DR 都不是
更长的答案:在所谓的异步操作中从中间件调用。在 redux 社区中,它被称为 "thunk" 或 "saga".
首先,一些定义:
- action: 普通对象
{ type: 'ACTION_TYPE', payload: { data } }
- action creator: returns action. 的函数
- async action: 从middleware. 调用的函数
- async action creator: returns async action 的函数
- 中间件: 一个可以处理所有动作,调度其他动作并可以访问存储状态的函数。
那么,我们从哪里调用业务逻辑呢?
如果仔细观察,您会发现我们不需要 async action 和 async action creator。我们可以有一个简单的 action 直接在 middleware.
中处理在 middleware 中,我们可以为每个 action 提供专用的 handler。这个 handler 的行为类似于 async action 但我们不这么称呼它。我们称它为 interactor.
所以一个新的定义:
interactor:本质上是 redux 中 async action 的抽象,但不是特定于 redux 的。 Interactor 获取数据、调用业务逻辑并发送结果 "actions".
middleware = (...) => {
// if(action.type == 'HIGH_LEVEL')
interactors[action.name]({ dispatch, params: action.payload })
}
const interactors = {
async highLevelAction({ dispatch, params }) {
dispatch({ loading: true });
const data = await api.getData(params.someId);
const processed = myPureLogic(data);
dispatch({ loading: false, data: processed });
}
}
发货方式:
dispatch({ type: 'HIGH_LEVEL', name: 'highLevelAction', { someId: 1 } })