redux
是react全家桶的一员,它试图为 React 应用提供「可预测化的状态管理」机制。- 就是可以将数据进行状态管理,在多个组件中进行运用
- 你可能需要安装的包
yarn add redux
yarn add react-redux
yarn add redux-saga
yarn add redux-thunk
yarn add redux-actions
复制代码
redux文件夹的划分
- 首先建立的一个
store
文件夹,下面有actions
文件夹,reducers
文件夹,action_types
文件夹(用来存放action.type的常量可以不用),还有一个index文件(用来导出合并之后的store
)
store的编写
- 也就是index.js文件怎么导出store
- 只有一个reducer的情况
// 1.引入createStore,专门用于创建redux中最为核心的store对象
import {createStore} from 'redux';
// 2.因为为Count组件服务的reducer
import countReducer from './count_reducers';
// 暴露store
export default createStore(countReducer)
复制代码
- 有多个reducer需要合并的情况
- 使用
combineReducers
来合并,他接收的是一个对象的形式
import countReducer from './reducers/countReducer'
import personReducer from './reducers/personReducer'
import {combineReducers,createStore} from 'redux';
export default createStore(combineReducers({
counter:countReducer,
person:personReducer
}))
复制代码
action的编写
action就是改变state的指令,有多少操作state的动作就会有多少action。实际上action就是向action 分为同步action和异步action:
- 同步action
import {INCREMENT,DECREMENT} from '../action_types/counter.actions.types'
export const increment = data =>({type:INCREMENT,data})
export const decrement = data =>({type:DECREMENT,data})
复制代码
reducer的编写
- reducer的本质是一个函数,接收:preState,action,返回加工后的状态
- reducer有两个作用:初始化状态,加工状态
import {INCREMENT,DECREMENT} from '../action_types/counter.actions.types'
const init = {
count:6
}
export default function countReducer(state=init,action){
//根据传递不同的类型执行不同的操作
switch (action.type) {
case INCREMENT:
return {
count:state.count+1
}
case DECREMENT:
return {
count:state.count-1
}
default:
return state
}
}
复制代码
使用connect创建出容器组件
- 首先在最外面的index.js文件中将总的store传递出去
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// 引用Provide组件包裹App组件
import {Provider} from 'react-redux'
import store from './store'
ReactDOM.render(
// 将store传递出去
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
复制代码
- 在需要使用store的组件中用connect创建出容器组件
- connect(mapStateToProps,mapDispatchToProps)(UI组件)
mapStateToProps
:映射状态,返回值是一个对象mapDispatchToProps
:映射操作状态的方法,返回值是一个对象
- mapDispatchToProps的创建有两种方法下面有例子
- 从props中就能获取store的数据,和操作action的方法
import React from 'react'
import {connect} from 'react-redux'
// 对应方法一
import {increment,decrement} from '../store/actions/countActions'
// 对于方法二
// import { bindActionCreators} from 'redux'
// import * as counterActions from '../store/actions/countActions'
function Count(props) {
return (
<div>
<h2>count:{props.count.count}</h2>
<button onClick={()=>{props.increment()}}>+1</button>
<button onClick={props.decrement}>-1</button>
</div>
)
}
// 这个state,是前面传递的store的值
const mapStateToProps = state =>({
count:state.counter
})
// 方法一
const mapDispatchToProps ={
increment:increment,
decrement:decrement,
}
// 方法二
// const mapDispatchToProps = dispatch=>(
// {
// ...bindActionCreators(counterActions,dispatch)
// }
// )
export default connect(mapStateToProps,mapDispatchToProps)(Count)
复制代码
使用redux-saga处理异步action
- 首先观察下文件结构
- 需要在之前的基础上从redux中引用
applyMiddleware
- 从redux-saga中引出createSagaMiddleware
import countReducer from './reducers/countReducer'
import personReducer from './reducers/personReducer'
import {combineReducers,createStore,applyMiddleware} from 'redux';
import rootSaga from './Saga/root.saga'
// 使用redux-saga解决异步情况
import createSagaMiddleware from 'redux-saga'
const sagaMiddleware = createSagaMiddleware()
export default createStore(combineReducers({
counter:countReducer,
person:personReducer
}),applyMiddleware(sagaMiddleware))
// 还需要run一下导出的saga,必须写在export后面
sagaMiddleware.run(rootSaga)
复制代码
- 创建一个root.saga.js文件,用来对所有的saga进行合并
// 对所有的saga进行合并操作
import {all} from 'redux-saga/effects'
import personSaga from './person.saga'
export default function* rootSaga(){
// 把需要合并的saga文件放到all里面
yield all([personSaga()])
}
复制代码
- 创建单个saga进行异步操作
import axios from 'axios'
import {takeEvery,put} from 'redux-saga/effects'
function* loadPerson(){
let data = yield axios.get('http://localhost:3005/api/getUsers').then(res=>{
return res.data
})
yield put({type:'load_person_success',data})
}
export default function* personSaga(){
// 接受到getPerson这个action后执行loadPerson这个方法
yield takeEvery('getPerson',loadPerson)
}
复制代码
看一下对应的reducer文件(personReducer.js)
import {ADDPERSON} from '../action_types/counter.actions.types'
const init = [{name:'zxx',age:18},{name:'hhy',age:20}]
export default function countReducer(state=init,action){
console.log('action',action);
switch (action.type) {
case ADDPERSON:
return [...state,action.data]
case 'load_person_success':
return [...state,...action.data]
default:
return state
}
}
复制代码
使用redux-thunk解决异步action
- 首先还是看下文件结构
- 在导出store的时候,引入中间件和thunk
import countReducer from './reducers/countReducer'
import personReducer from './reducers/personReducer'
import {combineReducers,createStore,applyMiddleware} from 'redux';
// 使用thunk解决异步情况
import thunk from 'redux-thunk'
export default createStore(combineReducers({
counter:countReducer,
person:personReducer
}),applyMiddleware(thunk))
复制代码
- 在action中进行异步操作
import axios from 'axios'
import {ADDPERSON} from '../action_types/counter.actions.types'
export const addPerson = data=>({type:ADDPERSON,data})
// redux-thunk来处理异步操作
export const getPerson =()=>async (dispatch)=>{
let persons = await axios.get('http://localhost:3005/api/getUsers').then(res=>{
return res.data
})
dispatch({type:'loadPersonSucess',data:persons})
}
复制代码
使用redux-actions来优化代码
- 在action文件中使用
import {createAction} from 'redux-actions'
// 不使用createAction
// export const increment = data =>({type:'increment',data})
// export const decrement = data =>({type:'decrement',data})
// 使用createAction
export const increment_action = createAction('increment')
export const decrement_action = createAction('decrement')
复制代码
- 在reducer文件中使用
import {handleActions as createReducer} from 'redux-actions'
import {increment_action,decrement_action} from '../action/count.action'
const initState = {count:0}
// createReducer接受两个参数,第一个参数是一个对象,key就是action,value就是操作的函数,第二个参数就是初始值
// 使用handleActions
export default createReducer({
// action.payload 可以接受传递过来的值
[increment_action]:(state,action)=>{return {count:state.count+action.payload}
},
[decrement_action]:(state,action)=>({count:state.count-1})
},initState)
// 不使用handleActions
// export default function countReducer (state={count:0},action){
// switch (action.type) {
// case 'increment':
// return {count:state.count+1}
// case 'decrement':
// return {count:state.count-1}
// default:
// return state
// }
// }
复制代码
- 最后看一下使用redux的这个组件
import React from 'react'
import {connect} from 'react-redux'
import * as counterAction from '../store/action/count.action'
import {bindActionCreators} from 'redux'
function Count(props) {
console.log(props);
return (
<div>
<h2>number:{props.count}</h2>
<button onClick={()=>{props.increment_action(5)}}>+1</button>
<button onClick={props.decrement_action}>-1</button>
</div>
)
}
const mapStateToProps = state =>({count:state.count.count})
// 自动生成action处理方法
const mapDispatchToProps = (dispatch)=>({
...bindActionCreators(counterAction,dispatch)
})
export default connect(mapStateToProps,mapDispatchToProps)(Count)
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END