Redux的使用

  • redux是react全家桶的一员,它试图为 React 应用提供「可预测化的状态管理」机制。
  • 就是可以将数据进行状态管理,在多个组件中进行运用

image.png

  • 你可能需要安装的包
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)

image.png

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传递出去

image.png

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

  • 首先观察下文件结构

image.png

  • 需要在之前的基础上从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)
}
复制代码

image.png
看一下对应的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

  • 首先还是看下文件结构

image.png

  • 在导出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中进行异步操作

image.png

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>
      &nbsp;
      <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
喜欢就支持一下吧
点赞0 分享