爱生活,爱编程,学习使我快乐
本文主要分享一个比较完善的redux的解决方案。
- 使用react-redux的Provider组件(提供器)包裹所有组件(或直接包裹根组件),使组件层级中的 connect() 方法都能够获得 Redux store。
- 使用”combineReducers”函数,把多个reducer(即多个模块)整合成一个大的reducer,并导出给store使用。
- 每个模块(如组件)文件夹中有一个自己的store文件夹,只处理本模块的逻辑。
- 使用immutable(不可修改的)库,把state转成immutable对象,避免state被修改而出现bug。
src
--App.js // 根组件
--store // 总store目录
--index.js // 总store入口
--reducer.js // 总reducer
--pages // 页面目录
--header // 组件
--index.js // 组件js文件
--style.js // 组件的样式文件
--store // 组件下的store(只针对本组件)
--index.js // 把本组件store下的constants、actionCreators、reducer一起包装并导出
--constants.js // 定义type常量
--actionCreators.js // 返回action对象
--reducer.js // 定义reducer及逻辑
使用react-redux的Provider组件包裹所有组件,把 store 作为 props 传递到每一个被 connect() 包装的组件。
src/App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Header from './pages/header';
function App() {
return (
<Provider store={store}>
<Header/>
{/*其它更多使用*/}
</Provider>
);
}
export default App;
- 使组件层级中的 connect() 方法都能够获得 Redux store,这样子内部所有组件就都有能力获取store的内容(通过connect链接store)。
- 可以使用connect的第一个参数mapStateToProps把state映射到props,第二个参数mapDispatchToProps 把dispatch映射到props。
- 如何设置了设置了第一个参数,state改变后会自动合并到组件的props;如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。
从本组件store中引用actionCreators,在组件中直接供dispatch使用。
src/pages/header/index.js
import React from 'react';
import { HeaderWrapper, SearchWrap, HeadInput } from './style';
import { CSSTransition } from 'react-transition-group';
import { connect } from 'react-redux';
import { actionCreators } from './store' // 从本组件store中引用actionCreators
const Header = (props) => {
const { focused, handleFocus, handleBlur } = props;
return (
<HeaderWrapper>
<SearchWrap>
<CSSTransition
in={focused}
timeout={300} // 动画执行1秒
classNames="slide"
>
<HeadInput
className = {focused ? "active" : ""}
onFocus={handleFocus}
onBlur={handleBlur}/>
</CSSTransition>
<span className = {focused ? "iconfont active" : "iconfont"}></span>
</SearchWrap>
</HeaderWrapper>
)
}
const mapStateToProps = (state) => {
return {
// focused: state.get('header').get('focused')
// 使用immutable的getIn方法连写,效果同上
focused: state.getIn(['header', 'focused'])
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleFocus () {
dispatch(actionCreators.searchFocus());
},
handleBlur () {
dispatch(actionCreators.searchBlur());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
src/store/reducer.js
import { combineReducers } from 'redux-immutable';
import headerReducer from '../pages/header/store/reducer'; // 引用组件中的子reducer
// 使用combineReducers方法整合多个子reducer
// 使用redux-immutable的combineReducers方法,返回的是immutable对象
const reducer = combineReducers({
header: headerReducer
})
export default reducer;
src/store/index.js
// 引入createStore方法
import { createStore } from 'redux';
// 引入reducer
import reducer from './reducer';
// 创建store,并把reducer中导出的方法传进来
const store = createStore(reducer);
// 如果要使用Redux DevTools,可如下设置
// const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export default store;
常量 constants
常量的作用是避免type字符串拼写错误导致出现不易排查的问题。
因为如果type是字符串的话,组件中action的type和reducer中的type如果因拼写错误而不一致,会导致处理失败,但也不会报错,很难排查问题。
而使用了常用,如果拼写错误会报错提示。
src/pages/header/store/constants.js
export const SEARCH_FOCUS = 'header/SEARCH_FOCUS'
export const SEARCH_BLUR = 'header/SEARCH_BLUR'
export const TEST_ADD = 'header/TEST_ADD'
actionCreators
actionCreators是个方法,返回一个action对象,也可以把方法的入参传递给reducer用来更新state
src/pages/header/store/actionCreators.js
import * as constants from './constants'
export const searchFocus = () => ({
type: constants.SEARCH_FOCUS
})
export const searchBlur = () => ({
type: constants.SEARCH_BLUR
})
// 可传入数据交给reducer来更新state
export const testAdd = (data) => ({
type: constants.TEST_ADD,
data: data
})
reducer 更新state 以及逻辑操作
使用immutable(不可修改的)库,把state转成immutable对象,避免state被修改而出现bug。
src/pages/header/store/reducer.js
import * as constants from './constants' // 导入常量
import { fromJS } from 'immutable'
// 使用immutable库,生成immutable对象(不可变的对象,避免修改state)
const defaultState = fromJS({
focused: false
})
export default (state = defaultState, action) => {
const {type} = action;
switch(type) {
case constants.SEARCH_FOCUS:
// immutable对象的set方法,会结合之前的immutable对象的值和设置的值,【返回一个全新的对象】
return state.set('focused', true);
case constants.SEARCH_BLUR:
return state.set('focused', false);
default:
return state;
}
}
组件store的入口文件
整合导入constants、actionCreators、reducer,并一起导出,方便外部统一使用
src/pages/header/store/index.js
import reducer from './reducer'
import * as actionCreators from './actionCreators'
import * as constants from './constants'
export {reducer, actionCreators, constants}