7、React的Redux
Redux理解
- 英文文档: https://redux.js.org/
- 中文文档: http://www.redux.org.cn/
- Github: https://github.com/reactjs/redux
- redux 是一个独立专门用于做状态管理的JS 库(不是react 插件库)
- 它可以用在react, angular, vue 等项目中, 但基本与react 配合使用
- 作用: 集中式管理react 应用中多个组件共享的状态
需要Redux时的情景
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
Redux基本使用
安装
yarn add redux为了更方便的管理
store,因此新建一个文件夹store用于专门存放关于store相关操作的代码store.js用于写创建stroe对象相关的代码
import { createStore } from 'redux' import { counter } from './reducers' // 生成一个store对象 const store = createStore(counter) // 内部第一次调用初始实例 export default storereducers.js用于编写一些修改状态的方法,返回将状态修改后的结果。这个函数用于与创建store对象时进行关联
// 包含reducer函数的模块 import { INCREMENT, DECREMENT } from './actions-types' export function counter (state = 0, action) { switch (action.type) { case INCREMENT: return state + action.data case DECREMENT: return state - action.data default: return state } }actions-types.js定义actions的type。
// 包含所有actions type的字符串 export const INCREMENT = 'INCREMENT' export const DECREMENT = 'DECREMENT'actions.js生成actions对象的函数
// 包含所有actions creator import { DECREMENT, INCREMENT } from "./actions-types"; // 增加 export const increment = (number) => ({ type: INCREMENT, data: number }) // 减少 export const decrement = (number) => ({ type: DECREMENT, data: number })
在入口文件使用
import store from './redux/store' function init () { ReactDOM.render( <App store={store} />, document.getElementById('root') ); } init() store.subscribe(function () { init() })在程序文件中调用
import { increment, decrement } from '../redux/actions' increment = () => { // 1. 获取增加的值 const number = this.select.value * 1 // 2. 计算新的count并更新 this.props.store.dispatch(increment(number)) }
react-redux
一个用于简化redux操作的react插件。主要对上一步进行改造。
安装插件
yarn add react-redux修改入口文件
import { Provider } from 'react-redux'; ReactDOM.render( <Provider store={store}><App /></Provider>, document.getElementById('root') );在app组件中暴露的不是类,而是
connect函数import { connect } from 'react-redux' import { increment, decrement } from '../redux/actions' class App extends Component {} export default connect((state) => ({ count: state }), { increment, decrement })(App)
异步处理
redux默认不支持异步处理。因此如果在redux中使用异步操作应该使用插件redux-thunk。
安装插件
yarn add redux-thunk修改创建
srore对象的结构import { createStore, applyMiddleware } from 'redux' import { counter } from './reducers' import thunk from 'redux-thunk'; // 生成一个store对象 const store = createStore(counter, applyMiddleware(thunk)) // 内部第一次调用初始实例 export default store编写异步逻辑,编辑
action.js文件// 异步action export const incrementAsync = (number) => { return dispatch => { setTimeout(() => { // 1s之后才会去执行action dispatch(increment(number)) }, 1000); } }
redux调试工具
谷歌浏览器安装插件
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd
项目安装插件
yarn add redux-devtools-extension在项目中引用插件(store中)
import { composeWithDevTools } from 'redux-devtools-extension' import thunk from 'redux-thunk'; const store = createStore(counter, composeWithDevTools(applyMiddleware(thunk)))
react-redux改造流程
创建好文件结构——创建
redux文件,并创建如下文件actions.js包含所有action creator(action的工厂函数)
actions-type.js包含所有action的type常量
reducers.js包含N个reducer函数。根据老的strate和action返回一个新的state
store.js核心管理对象
入口文件引入
import React from 'react'; import ReactDOM from 'react-dom'; // 引入Provider import { Provider } from 'react-redux' // 引入核心对象 import store from './redux/store' import App from './components/app/app.jsx' // 将根组件进行包裹 ReactDOM.render((<Provider store={store}><App /></Provider>), document.getElementById('root'));在根组件中引用
import { addComent, deleteComent } from '../../redux/actions' class App extends Component { static propTypes = { comments: propTypes.array.isRequired, addComent: propTypes.func.isRequired, deleteComent: propTypes.func.isRequired } } // 第一个参数取决于数据定义格式 export default connect((state) => ({ comments: state }), { // 以下来源于action addComent, deleteComent })(App)编辑
action-type.js文件,定义type的常量即对数据操作的类型。
// 添加评论 export const ADD_COMMENT = 'add_commont' // 删除评论 export const DELETE_COMMENT = 'delete_comment'编辑
actions.js文件。// 包含所有action creator(action的工厂函数) import { ADD_COMMENT, DELETE_COMMENT } from './action-type' // 同步添加 export const addComent = (comment) => ({ type: ADD_COMMENT, data: comment }) // 同步删除 export const deleteComent = (index) => ({ type: DELETE_COMMENT, data: index })编辑
reducer.js文件// 包含N个reducer函数 // 根据老的strate和action返回一个新的state import { ADD_COMMENT, DELETE_COMMENT } from './action-type' const initComments = [ { username: 'Tom', content: 'react挺好的' }, { username: 'Tom', content: 'react太难了' } ] export function comments (state = initComments, action) { switch (action.type) { case ADD_COMMENT: return [action.data, ...state] case DELETE_COMMENT: return state.filter((comment, index) => action.data !== index) default: return state } }编辑
store.js文件// 核心管理对象 import { createStore, applyMiddleware } from 'redux' import { comments } from './reducers' import thunk from 'redux-thunk' import { composeWithDevTools } from 'redux-devtools-extension' export default createStore(comments, composeWithDevTools(applyMiddleware(thunk)) )
添加异步操作
在
actions.js文件中添加异步操作// 包含所有action creator(action的工厂函数) import { ADD_COMMENT, DELETE_COMMENT, RECEIVE_COMMENTS } from './action-type' // 同步接收comments const receiveComments = (comments) => ({ type: RECEIVE_COMMENTS, data: comments }) // 异步获取 export const getComment = () => { return dispatch => { // 模拟异步请求 setTimeout(() => { const comments = [ { username: 'Tom', content: 'react挺好的' }, { username: 'Tom', content: 'react太难了' } ] // 分发一个同步actions dispatch(receiveComments(comments)) }, 1000); } }在
actions-type.js中定义类型// 异步获取 export const RECEIVE_COMMENTS = 'receive_comment'修改
reducers.js// 包含N个reducer函数 // 根据老的strate和action返回一个新的state import { ADD_COMMENT, DELETE_COMMENT, RECEIVE_COMMENTS } from './action-type' export function comments (state = initComments, action) { switch (action.type) { case ADD_COMMENT: return [action.data, ...state] case DELETE_COMMENT: return state.filter((comment, index) => action.data !== index) case RECEIVE_COMMENTS: return action.data default: return state } }在根组件的生命周期中触发
class App extends Component { componentDidMount() { // 异步获取评论数组 this.props.getComment() } } // 第一个参数取决于数据定义格式 export default connect((state) => ({ comments: state }), { // 以下来源于action addComent, deleteComent, getComment })(App)
reducers暴露多个
import { combineReducers } from 'redux'
function counter(){}
function comments(){}
export default combineReducers({
counter,
comments
})在创建对象时管理的为reducers
import reducers from './reducers'
export default createStore(
reducers,
)此时redux暴露的为对象结构,
{counter:xx,comments:xx}










