Redux应用一:单个reducer

226 阅读4分钟

image.png

不应用react-redux

创建一个store文件

  • index.js 用来创建store和应用中间件等
import { createStore } from 'redux'
import reducer from './reducer.js'
// 创建store
const store = createStore(reducer)
export default store
  • reducer.js用来创建reducer(state, action)函数,传给createStore创建store,
// 返回一个reducer函数,让createStore用来创建store
// 导入actionTypes.js中的type类型,方便我们进行识别操作
import {
  A,
  B
} from './actionTypes.js'

// state初始化
const defaultState = {
  valueA: '',
  valueB: ''
}

// 只能间接修改state
const reducer = (state = defaultState, action) => {
  if (action.type === A) {
    const newState = {...state}
    newState.valueA = action.value
    return newState
  } else if (action.type === B) {
    const newState = {...state}
    newState.valueB = action.value
    return newState
  }
  return state
}

export default reducer
  • actionTypes.js 用来统一地方定义action对象的type类型,方便我们进行统一管理
// 用来定义action的类型,方便进行统一管理
export const A = 'A'
export const B = 'B'
  • actionCreators.js 用于返回action对象
// 导入actionTypes.js中的type类型,方便我们进行识别操作
import {
  A,
  B
} from './actionTypes'

// 以函数的形式获取返回值,为action对象,其中action对象必须包含type属性,方便我们进行识别操作
export const setActionA = (value) => {
  return {
    type: A,
    value
  }
}
export const setActionB = (value) => {
  return {
    type: B,
    value
  }
}
  • ReduxExample组件中使用
import React from 'react'
// 导入store
import store from './../../store'
// 导入action
import {
  setActionA
} from './../../store/actionCreators'
class ReduxExample extends React.Component {
  constructor(props) {
    super(props)
    this.state = store.getState()

    // 监听store中的数据变化执行subscribe
    this.handleStoreChange = this.handleStoreChange.bind(this)
    store.subscribe(this.handleStoreChange);
  }
  render() {
    return (
      <div>
        <h2>redux-example</h2>
        <div>
          {this.state.valueA}
        </div>
      </div>
    )
  }
  componentDidMount() {
    console.log(store.getState())
    const actionA = setActionA('A')
    setTimeout(() => {
      store.dispatch(actionA) // dispatch修改state,从而触发store.subscribe重新执行
      console.log(this.state)
      console.log(store.getState())
    }, 1000)
  }
  handleStoreChange() {
    this.setState(store.getState())
  }
}
export default ReduxExample

image.png

使用Chrome的Redux DevTools插件,方便我们进行开发

image.png

// store/index.js
import { createStore, compose } from 'redux'
import reducer from './reducer'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// 创建store
const store = createStore(reducer, composeEnhancers())

export default store

image.png

image.png

应用react-redux

image.png

// App.js 组件
import './App.css';
import ReduxExample from './pages/reduxtest/Test'
import { Provider } from 'react-redux'
import store from './store'

function App() {
  return (
    <Provider store={store}>
      <ReduxExample/>
    </Provider>
  );
}

export default App;
// ReduxExample组件

import React from 'react'
// 导入action
import {
  setActionA
} from './../../store/actionCreators'
import { connect } from 'react-redux'
class ReduxExample extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'test'
    }
  }
  render() {
    const { valueA, changeValueA } = this.props
    return (
      <div>
        <h2>redux-example</h2>
        {
          valueA
        }
        <button onClick={changeValueA}>change</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    valueA: state.valueA,
    valueB: state.valueB
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    changeValueA: () => {
      dispatch(setActionA('A'))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(ReduxExample)

image.png

image.png

Immutable.js 对象来管理 store 中的数据

  • 作用:保证state不被修改
  • 参考文档
  • 安装 npm install immutable 或者 yarn add immutable
  • 主要是通过formJS将JS对象转化为immutable对象,然后通过immutable提供的set和get方法进行操作数据

image.png

// store/reducer.js
// 返回一个reducer函数,让createStore用来创建store
// 导入actionTypes.js中的type类型,方便我们进行识别操作
import {
  A,
  B
} from './actionTypes.js'

// formJS将JS对象转化为immutable对象
import { fromJS } from 'immutable'
const defaultState = fromJS({
  valueA: '',
  valueB: ''
})
// state初始化
// const defaultState = {
//   valueA: '',
//   valueB: ''
// }

// 只能间接修改state
const reducer = (state = defaultState, action) => {
  if (action.type === A) {
    return state.set('valueA', action.value)
  } else if (action.type === B) {
    return state.set('valueB', action.value)
  }
  return state
}

export default reducer
// ReduxExample组件
import React from 'react'
// 导入action
import {
  setActionA,
  setActionB
} from './../../store/actionCreators'
import { connect } from 'react-redux'
class ReduxExample extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'test'
    }
  }
  render() {
    const { valueA, changeValueA } = this.props
    return (
      <div>
        <h2>redux-example</h2>
        {
          valueA
        }
        <button onClick={changeValueA}>change</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    valueA: state.get('valueA'),
    valueB: state.get('valueB')
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    changeValueA: () => {
      dispatch(setActionA('A'))
      dispatch(setActionB('B'))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(ReduxExample)

image.png

image.png

使用redux-thunk插件进行异步操作

参考文档

dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。 换言之,中间件都是对store.dispatch()的增强

  • redux-thunk中将异步请求放到 actionCreators 里面
  • redux-thunk 中间件实际上是对 dispatch 进行了处理而已,原本只能返回对象,现在能返回函数,当 dispatch 的实参是函数时就会自动执行.

Redux中间件.png

  • 安装 npm install redux-thunk 或者 yarn add redux-thunk
  • 使用

image.png

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

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// 创建store
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

export default store
// store/actionCreators.js
// 导入actionTypes.js中的type类型,方便我们进行识别操作
import {
  A,
  B
} from './actionTypes'

// 返回一个异步的函数,一秒后进行操作
const waitRun = (val) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(val)
    }, 1000)
  })
}

// 以函数的形式获取返回值,为action对象,其中action对象必须包含type属性,方便我们进行识别操作
const setActionA = (value) => {
  return {
    type: A,
    value
  }
}
export const setActionB = (value) => {
  return {
    type: B,
    value
  }
}

export const waitOneSeconds = (val) => {
  return (dispatch) => {
    waitRun(val).then(res => {
      const action = setActionA(res)
      dispatch(action)
    })
  }
}

image.png

// ReduxExample组件
import React from 'react'
// 导入action
import {
  waitOneSeconds
} from './../../store/actionCreators'
import { connect } from 'react-redux'
class ReduxExample extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'test'
    }
  }
  render() {
    const { valueA, changeValueA } = this.props
    return (
      <div>
        <h2>redux-example</h2>
        {
          valueA
        }
        <button onClick={changeValueA}>change</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    valueA: state.get('valueA'),
    valueB: state.get('valueB')
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    changeValueA: () => {
      dispatch(waitOneSeconds('A'))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(ReduxExample)

image.png

image.png

使用redux-saga进行异步操作

此处只进行基本用法介绍,自己也还在继续深入学习

  • Redux-saga 和 Redux-thunk 一样也是用来处理异步操作的,只是 Redux-saga 能独立出一个单独文件来写 api

参考文档

中文文档

其他参考博文

  • 安装 npm install redux-saga 或者 yarn add redux-saga

redux-saga使用详细介绍