Redux
安装
# NPM
npm install redux
# Yarn
yarn add redux
state
- state就是存放数据的地方
- state数据需要通过
reducer
来管理 - 发起reducer需要通过
dispatch
- dispatch的参数是一个
action
总结来说,state
的修改需要通过dispatch
发起一个action
,然后通过reducers
返回一个新的state。
Action
- action是把数据从应用传到store的有效载荷,是store数据的唯一来源。
- 需要通过
store.dispatch()
将action
传到store
- 格式中type是固定的字段,其他字段可以自定义
// 一个简单的action函数
const ADD_TODO = 'ADD_TODO';
function addTodo(payload) {
return {
type: ADD_TODO, // 这里一般会做成一个常量,避免书写是出错
payload, // 需要传给reducer的数据
}
}
// 用法
dispatch(addTodo(0))
Reducer
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新state。
设计state结构
- 在 Redux 应用中,所有的 state 都被保存在一个单一对象中。
Action 处理
- 需要通过type区分出来需要如何修改数据,调用不同的方法
- 修改state的数据,只能返回新的state,不可以直接修改state的数据
- reducers接受两个参数,一个是state, 一个是action返回的对象
const ADD_TODO = 'ADD_TODO';
// 初始化state
const initialState = {
todos: []
}
// 处理todos部分的数据
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
...action.payload
]
default:
return state
}
return state;
}
// 统一分配函数,这里讲state的数据分配给不同的方法处理,每个函数只处理state的一部分,如果业务和数据是分开的,可以这样拆分
function todoApp(state, action) {
return {
todos: todos(state.todos, action)
}
}
模块化reducers
在过多的reducers中,可以通过不同的模块进行拆分,然后通过combineReducers
将拆分的合并起来。
combineReducers()
所做的只是生成一个函数,这个函数来调用你的一系列 reducer,每个 reducer 根据它们的 key 来筛选出 state 中的一部分数据并处理,然后这个生成的函数再将所有 reducer 的结果合并成一个大的对象。
import { combineReducers } from 'redux'
const todoApp = combineReducers({
todos, // z这样todos中只能访问到todos的state了,todos就是模块的名称,要访问todos中的数据,需要通过todos.todos来访问
})
// todoApp这两种写法是一样的
function todoApp(state, action) {
return {
todos: todos(state.todos, action)
}
}
export default todoApp
命名空间问题
由于redux并没有采用命名空间这种方式来区分模块,模块在进行diapatch时是对根store抛发的,所以他会触发所有的子reducer,因此各个模块之间要明确好type的格式
Store
- 维持应用的 state;
- 提供
getState()
方法获取 state; - 提供
dispatch(action)
方法更新 state; - 通过
subscribe(listener)
注册监听器; - 通过
subscribe(listener)
返回的函数注销监听器。
创建state
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp) // 获取所有的state
发起Action,更新数据
import { addTodo } from './actions'
// 这样就可以修改todos的值了
store.dispatch(addTodo('learn about actions'))
react-redux
安装
npm install --save react-redux
传入Store
- 通过
Provider
容器讲store传入组件中 - 最好是讲该容器组件放到根组件中
import React from 'react'
import { Provider } from 'react-redux'
import store from './store/index'
import App from './compontns/App'
render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
组件中使用state数据
- 通过
connect
将state和dispatch等方法注入到组件里面 - connect有两个参数
mapStateToProps
、mapDispatchToProps
-
mapStateToProps
是一个函数,接受state
作为参数,返回一个对象 -
mapDispatchToProps
是函数时:有两个参数,一个是disaptch
用来调用action更新store数据,另一个是当前组件的props
-
mapDispatchToProps
是对象时:键值应该是一个函数,被当做action
,回自动发出该action
// connect
import { connect } from 'react-redux'
// 这里的state是总的那个state
const mapStateToProps = state => {
return {
todos: state.todos // 将todos 返回到组件的props中,key为todos
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
// 这里的方法return后就可以通过props来获取该方法了,在组件中正常进行调用
onClick: () => {
dispatch({
type: ADD_TODO,
payload: ownProps.todos
})
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Home)// Home是当前组件的名称
redux-saga
安装
npm install redux-sage
yarn add redux-saga
简介
- redux-saga是一个用于管理redux应用一部操作的中间件
- redux-saga是通过generator函数创建的
配置
import {createSrote, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducers from './reducers';
import rootSaga from './saga' // saga文件
const sageMiddleware = createSagaMiddleware();
// 讲saga引入store中
let store = createStore(reducers, applyMiddleware(sagaMiddleware));
// 运行saga
sagaMiddleware.run(rootSaga);
export default store;
saga方法书写
import { call, put, takeEvery } from 'redux-saga/effects'
const getData = () => {
// call 是执行异步操作的
const products = yield call(Api.fetch, '/products')
// put发起action的和dispatch相似
yield put({
type: ADD_TODO,
payload: products
})
}
function *stateSaga() {
yield takeEvery(ADD_TODO, getData)
yield takeEvery(ADD_TO, getInfo)
}
export const stateSaga = () => {
}
总结
-
react-redux
是在action发起后监听到需要进行处理的则进行处理,是个在action
后面和reducer
前面的那一步骤的 -
takeEvery
允许多个getData实例同时启动 - 如果要拦截多个action,可以使用多个
takeEvery
,不用考虑先后顺序,这个是可以同时触发的。