将组件中的业务逻辑提取到redux的reducer中
先来看一个组件(视图)中包含太多业务逻辑的例子:
// .app/modules/someModule/MyComponent.js
import * as Actions from './actions';
import {connect} from 'react-redux';
class MyComponent extends React.Component{
componentDidMount() {
const {someState, otherState, someStateNotToBeRendered, dispatch, someValueFromComponent} = this.props;
//bad, 业务逻辑
//这里根据someState, otherState, someStateNotToBeRendered上的数据和从其他组件传递过来的属性someValueFromComponent做了很多业务逻辑处理
//最后得到了`init`这个`action`需要的参数
const finalValue = bussinessLogic(someState, otherState, someStateNotToBeRendered, someValueFromComponent);
//if条件判断语句也可能是业务逻辑判断,还有几个同步action, 应该移动到actionCreator中,
dispatch(Actions.actionOne());
dispatch(Actions.actionThree());
if(finalValue === 'someValue') {
dispatch(Actions.initialize(finalValue));
}
}
handleClick = () => {
const {someState, otherState, dispatch} = this.props;
//bad, 业务逻辑
//这里用someState和otherState上的数据做了很多逻辑处理
const finalValue = caculateFinalValue(someState, otherState);
dispatch(Actions.someAction(finalValue));
//bad, dispatch了很多action
dispatch(Actions.actionOne());
//使用了promise middleware的action
dispatch(Actions.actionTwo()).then((state) => {
const {someState: newSomeState, otherState: newOtherState} = state;
const finalValueAgain = caculateSomeFinalValue(newSomeState, newOtherState);
dispatch(Actions.actionThree(finalValueAgain));
});
}
render() {
const {someState} = this.props;
const {someData} = someState;
//bad, 业务逻辑
const someDataFormat = Util.dataFormat(someData);
return (
<div>{someDataFormat}</div>
)
}
}
export default connect(s => ({
someState: s.someState,
//bad
otherState: s.otherState
someStateNotToBeRendered: s.someStateNotToBeRendered
})
)(MyComponent);
// ./app/modules/someModule/actions.js
export const actionOne = () => ({
type: 'actionOne'
});
export const actionTwo = () => ({
type: 'actionTwo'
});
export const actionThree = (value) => ({
type: 'actionThree'
});
export const someAction = () => ({
type: 'someAction'
})
export const initialize = (value) => ({
type: 'initialize',
params: value
})
- 使用
react-redux的connect高阶组件给组件注入redux``store上的数据时,应该只注入该组件需要渲染的数据,因为view层仅仅需要渲染的数据。上面的例子中给组件props上注入的someStateNotToBeRendered和otherState,组件并不需要渲染这两个数据,仅仅是为了做业务逻辑处理,在componentDidMount中构造了init``action需要的参数。导致的问题就是,组件mount后,当这两个数据经过各自的reducer返回各自新的引用时,组件会走componentWillReceiveProps,最后再次render一遍,这显然是不合理的。 - 对于上述例子中
componentDidMount中bussinessLogic这个构造action参数的逻辑,我们应该将构造参数的代码放在redux-thunk中,见后面的例子。 - 这里我们需要使用
redux-thunk中间件进行改造
// ./app/modules/someModule/MyComponent.js
import * as Actions from './actions';
import {connect} from 'react-redux';
class MyComponent extends React.Component{
componentDidMount() {
const {dispatch} = this.props;
dispatch(Actions.init());
}
handleClick = () => {
}
render() {
const {}
return (
<div></div>
)
}
}
export default connect(s => ({
someState: s.someState
}))(MyComponent);
// ./modules/someModule/action.js
export const actionOne = () => ({
type: 'actionOne'
});
export const actionTwo = () => ({
type: 'actionTwo'
});
export const actionThree = (value) => ({
type: 'actionThree'
});
export const someAction = () => ({
type: 'someAction'
})
export const initialize = (value) => ({
type: 'initialize',
params: value
})
export const init = (params) => {
const someValueMayBeUse = '';
return (dispatch, getState) => {
dispatch(actionOne());
dispatch(actionThree());
const {otherState, someStateNotToBeRendered, someState} = getState();
const finalValue = bussinessLogic(someState, otherState, someStateNotToBeRendered);
//流程控制
if(someState.isShow) {
dispatch(actionTwo());
}
if(finalValue === 'someValue') {
dispatch(initialize(finalValue));
}
dispatch(someAsyncAction()).then(() => {
dispatch(fxxk());
})
}
}
initactionCreator通过redux-thunk整合了actionOne,actionTwo,initialize三个actionCreator,initialize这个actionCreator需要一个参数,这个参数是通过store上的otherState,someStateNotToBeRendered,someState这三个数据,进行一些逻辑处理(bussinessLogic)得出的,通过redux-thunk的getState方法,我们可以得到当前store,从而取得store上需要的数据,进行下一个actionCreator的参数构造,或者进行一些流程控制。
以上就是我在实际使用react中的一些小总结。