2.React之 redux、react-redux、redux-thunk

858 阅读4分钟

1、redux

redux 是类似vuex的状态管理组件 使用 createStore创建store来管理

具体使用如下:

import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const enhancer = composeEnhancers(
  applyMiddleware(thunk) // 使用thunk中间件
)

const store = createStore(reducer, enhancer)

export default store

注意:在使用devtools时需要用到composeEnhancers来使用,中间件需要使用 applyMiddleware,redux-thunk接下来在详细说明

store目录下

actionTypes.js
actionCreator.js
index.js
reducer.js

1.actionTypes.js

记录action常量,保证不会出错(类似vuex中Mutations)

export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_LIST = 'add_todo_list';
export const DELETE_ITEM = 'delete_item';
export const INIT_LIST  = 'init_list';

2.actionCreators.js

action创建管理,返回一个action,这里理解为类似vuex中的action

import * as types from './actionTypes';
import axios from 'axios';

export const getTodoLists = (value) => ({
    type: types.INIT_LIST,
    value
})

// 这里用到了redux-thunk来保证可以返回一个函数类型的action来执行ajax异步请求
export const initList = () => {
    return (dispatch) => {
        axios.post('/api/todolist').then((res) => {
            dispatch(getTodoLists(res.data.data));
        }).catch(() => {
            dispatch(getTodoLists(['暂无数据']));
        })
    }
}

3.reducer.js

reducer相当于记录本,store的处理器,用于接收所有action并处理数据,设置state

import { ADD_ITEM, CHANGE_INPUT, DELETE_ITEM } from './actionTypes'

const defaultState = {
  inputValue: '123',
  list: []
}

export default (state = defaultState, action) => {
  if (action.type === CHANGE_INPUT) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }
  if (action.type === ADD_ITEM) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }
  if (action.type === DELETE_ITEM) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.splice(action.index, 1)
    return newState
  }
  return state
}

但随着业务的增多,reducer不可能一直写下去,这里就要分模块进行处理,类似vuex中的modules,每个模块自己处理自己的state,action,reducer等,这里就要使用react-redux来进行配置

2、react-redux

在React-redux 中有两个比较关键的概念:Provider和connect方法。

Provider

一般我们都将顶层组件包裹在Provider组件之中,这样的话,所有组件就都可以在react-redux的控制之下了,但是store必须作为参数放到Provider组件中去

import { Provider } from 'react-redux'
function App() {
  return (
    <Provider store={store}>
     <Header/>
    </Provider>
  )
}

这个组件的目的是让所有组件都能够访问到Redux中的数据。

connect方法

在组件内使用

import React from 'react'
import { connect } from 'react-redux'
import { getAddItemAction, getDeleteItemAction, getInputChangeAction } from './store/actionCreator' // connect可以获取store

const TodoList = (props) => {
  const { inputValue, list, handleInputChange, handleClick, handleDelete } = props
  return (
    <div>
      <input value={inputValue} onChange={handleInputChange}/>
      <button onClick={handleClick}>add</button>
      <ul>
        {
          list.map((item, index) => {
            return (
              <li key={index} onClick={handleDelete}>{item}</li>
            )
          })
        }
      </ul>
    </div>
  )
}

// 映射store 的state
const mapStateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list
  }
}

// 映射store dispatch
const mapDispatchToProps = (dispatch) => {
  return {
    handleInputChange(e) {
      const action = getInputChangeAction(e.target.value)
      dispatch(action)
    },
    handleClick() {
      const action = getAddItemAction()
      dispatch(action)
    },
    handleDelete(index) {
      const action = getDeleteItemAction(index)
      dispatch(action)
    }
  }
}

// 表示让组件和store做连接,必须保证当前组件在Provider组件中
// content第一个参数,是连接规则,即把state映射为props中的数据,优点类似Vue中的getter
// 第二个参数是派发映射关系,即将store.dispatch映射至某个方法里
// TodoList是ui组件,但是通过connect连接后,返回的结果就是个容器组件(包含数据和方法)
export default connect(mapStateToProps, mapDispatchToProps)(TodoList)

根目录store中的reducer就可以这么拆分

import { combineReducers } from 'redux'
import { reducer as headerReducer } from '../components/Header/store'
import { reducer as homeReducer } from '../pages/home/store'
import { reducer as detailReducer } from '../pages/detail/store'
import { reducer as loginReducer } from '../pages/login/store'

// 类似于vuex的module合并,会将这部分的内容封装至不同的参数下单独管理即header:{header单独的state状态管理}
export default combineReducers({
  header: headerReducer,
  home: homeReducer,
  detail: detailReducer,
  login: loginReducer
})

PureComponent 与 Compnent 的使用

当组件中使用redux 时, 组件需要与 react-redux 中的 connect 配合使用,当store中的数据发生变化的时候, 每个组件都会重新渲染, 这显然不是我们想要的,我们可以使用生命周期的钩子shouldComponentUpdate 判断是否需要重新渲染,但是我们最好配合 react 中的PureComponent 使用, 将class App extends Compnent 中的 Compnent 换成 PureComponent 就可以解决 。

class Home extends PureComponent

// 继承了PureComponent,下方的判断即可省略
shouldComponentUpdate(nextProps, nextState, nextContext) {
    return this.props.data !== nextProps.data
}

3、react-thunk

是一个辅助action可以派发ajax时间函数的中间件,使用非常简单

只需要在store创建的时候使用applyMiddleware创建即可

import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const enhancer = composeEnhancers(
  applyMiddleware(thunk) // 使用thunk中间件
)

const store = createStore(reducer, enhancer)

export default store

在action创建管理,就可以返回一个函数来辅助ajax请求响应

import * as types from './actionTypes';
import axios from 'axios';

// 正常的需要返回一个对象,来提供dispatch派发action
export const getTodoLists = (value) => ({
    type: types.INIT_LIST,
    value
})

// 这里用到了redux-thunk来保证可以返回一个函数类型的action来执行ajax异步请求
export const initList = () => {
    return (dispatch) => {
        axios.post('/api/todolist').then((res) => {
            dispatch(getTodoLists(res.data.data));
        }).catch(() => {
            dispatch(getTodoLists(['暂无数据']));
        })
    }
}

相关连接

最近在学习react开发,整理几篇笔记方便自己查询使用,下面是连接地址

1.React 之 react-transition-group

2.React之 redux、react-redux、redux-thunk

3.React 之 immutable 和 redux-immutable

4.React 之react-router-dom

5.React 之 react-loadable

6.React 基础记录

7.React 使用less等预处理器配置