本文介绍redux的使用
-
安装
cnpm install redux --save cnpm install react-redux --save cnpm install redux-devtools --save-dev 如果你之前使用过vuex,我相信redux对于你来说就是易如反掌 redux官网将的很杂很乱,但是实用的东西就那么点
-
action
action就是一个对象,用来描述你要修改store状态树中的数据 { type: 'change_name', name: 'yejiawei' } type字段必须要有,这是约定
-
action创建函数
正常情况下,你需要给每一个action定义一个函数,从而方便调用 export function changeName (value) { return { type: 'change_name', name: value } }
-
Reducer
Reducer的作用,就是将不同的action汇总,然后返回相应的state const initialState = { name: 'haha' } function firstDemo (state = initialState, action) { switch (action.type) { case "change_name": return Object.assign({},state,{ name: action.name }) default: return state } } 返回值必须是全新的
-
拆分reducer
实际开发中都是模块化的,有必要将不同模块的reducer分开 import { combineReducers } from 'redux' combineReducers({firstDemo,firstDemo1})
-
store
创建store是非常简单的 import { createStore } from 'redux' 将上面创建的reducer当做参数传递即可 let store = createStore(firstDemo) store.getState() // 获取store中的数据 let unsubscribe = store.subscribe( () => { ... } ) // 监听器 store.dispatch(changeName('yejiawei')) // 调用action修改store中的state unsubscribe() // 注销监听器
-
在react组件中使用redux
下面我将列出,正常项目开发的结构 index.js import React from 'react' import ReactDOM from 'react-dom' import { Provider } from 'react-redux' import store from './store.js' import App from './app.js' ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ) 使用 Provider 组件传递store到react组件中 app.js import React from 'react' import MyComponent1 from './component1.js' import { connect } from 'react-redux' class MyComponent extends React.Component { render () { return ( <div> <MyComponent1 {...this.props}></MyComponent1> </div> ) } } function appWant(state) { return state } export default connect(appWant)(MyComponent) 使用connect方法将react组件连接到redux中,接受一个回调函数,并且回调函数的参数就是store中的state ** 原则,使用connect方法尽量只在容器组件中使用,其余的子组件如果也想访问store,就通过props传递即可 store.js import { createStore } from 'redux' const initialState = { message: 'yejiawei' } function firstApp (state = initialState, action) { switch (action.type) { case "change_message": return Object.assign({},state,{ message: action.message }) default: return state } } let store = createStore(firstApp); export default store 此文件专门用来管理和生成store的,同时还可以将reducer专门再生成一个reducer.js管理 component1.js 此组件代表类似的子组件 import React from 'react' import { delayData } from './actions.js' class MyComponent extends React.Component { componentDidMount() { this.props.dispatch(changeMessage('我改变了')) } render() { return ( <div style={{"height": "200px","width": "200px","background": "red","position": "absolute","top": "100px", "left": 0}}>我是组件一{this.props.message}</div> ) } } export default MyComponent 在子组件中访问store中的state和dispatch通过props直接访问即可 actions.js 此文件专门用来处理redux中的action生成函数 export function changeMessage (text) { return { type: 'change_message', message: text } }
-
在react组件中使用redux补充
上面讲到的connect方法,还可以传递其他参数 注意到我们传递给connect方法的参数是如下的这个函数 function appWant(state) { return state } 这个函数会在state改变的时候更新整个app组件,也就是说不管你在哪里dispatch了,那么整个app都会重新更新,性能损失 所以可以选择只传递一部分state,如下 function appWant(state,ownProps) { return { age: state.age } } 然后在其他的组件中也调用connect方法,管理自己的state,而不是只通过props传递,这样可以提高性能 另外也可以把action单独传递或者传递一部分,我不建议这样做,对性能没有任何提高,反而提升代码复杂度,直接使用dispatch简单清晰明了 在app.js文件中改成如下代码 import React from 'react' import MyComponent1 from './component1.js' import { connect } from 'react-redux' import { bindActionCreators } from 'redux'; import { delayData } from './actions.js' class MyComponent extends React.Component { render () { return ( <div> <MyComponent1 {...this.props}></MyComponent1> </div> ) } } function appWant(state) { return { age: state.age } } function funcWant(dispatch) { return { demo: bindActionCreators({delayData},dispatch) } } export default connect(appWant,funcWant)(MyComponent) 然后再component1.js中,就不需要通过dispatch调用了 this.props.demo.delayData('我又变了');
-
异步action
上面讲的内容是同步的,也就是说dispatch方法调用后,store中的state立即发生改变 那么,现在有一个需求是,dispatch的写法不发生任何改变,还可以进行异步操作 如何操作?只需要将action返回一个函数,然后在函数里面进行异步处理就完事儿了 要实现这个操作就要借助 redux-thunk-middleware 中间件 安装 cnpm install --save redux-thunk 然后将上面的store.js文件改成下面的 import { createStore, applyMiddleware } from 'redux' // 导入applyMiddleware方法用来使用中间件 import thunkMiddleware from 'redux-thunk' // 导入中间件 const initialState = { message: 'yejiawei' } function firstApp (state = initialState, action) { switch (action.type) { case "change_message": return Object.assign({},state,{ message: action.message }) default: return state } } let store = createStore(firstApp,applyMiddleware(thunkMiddleware)); // 将中间件应用于store中 export default store 然后再actions.js中添加一个异步action export function delayData (value) { return (dispatch) => { setTimeout( () => { dispatch(changeMessage(value)) },1000 ) } } 最后,直接在component1.js文件中直接调用即可 import React from 'react' import { delayData } from './actions.js' class MyComponent extends React.Component { componentDidMount() { this.props.dispatch(delayData('我改变了')) } render() { return ( <div style={{"height": "200px","width": "200px","background": "red","position": "absolute","top": "100px", "left": 0}}>我是组件一{this.props.message}</div> ) } } export default MyComponent
-
异步action的补充一
上面在定义异步action时,在返回的函数里面传递了dispatch参数,其实它还支持如下的参数 还是借助上面的例子 传递getState获取store中的state export function delayData (value) { return (dispatch,getState) => { setTimeout( () => { dispatch(changeMessage(value)) console.log(getState()) },1000 ) } } 传递自定义参数 在store中将创建store的代码改成 let store = createStore(firstApp,applyMiddleware(thunkMiddleware.withExtraArgument( {a: 'aaa', b: 'bbb'} ))); 然后再actions.js中获取参数 export function delayData (value) { return (dispatch, getState, {a,b}) => { setTimeout( () => { dispatch(changeMessage(value)) console.log(a,b) console.log(getState()) },1000 ) } }