知识总结 React【Redux】

82 阅读4分钟

Redux

概念

是什么

  1. redux是一个专门用于做状态管理的JS库(不是react插件库)。
  2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用。vue有vuex可以使用。
  3. 作用: 集中式管理react应用中多个组件共享的状态。

做什么

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)。
  2. 一个组件需要改变另一个组件的状态(通信)。
  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。

工作原理

image.png

三个核心概念

action

动作的对象,包含2个属性

  • type:标识属性, 值为字符串, 唯一, 必要属性
  • data:数据属性, 值类型任意, 可选属性

例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }

import React,{ Component } from "react";
import store from "./redux/store"; // 引入store

class App extends Component {
  // 组件挂载完毕后监听store的data值
  componentDidMount() {
    store.subscribe(()=>{
      this.setState({})
    })
  }
  // 调用action方法改变数据
  handel = () => {
    const value = 1
    store.dispatch({type:'add',data:value})
  }
  render() {
    return (
      <>
      <div>{store.getState()}</div>
      <button onClick={this.handel}>+</button>
      </>
    )
  }
}

reducer

  1. 用于初始化状态、加工状态。
  2. 本质上是一个函数。
  3. 有两个参数:
    • preState:之前的状态
    • action:动作对象
const initNum = 0
export default function myReducer(preState = initNum, action) {
  const {type,data} = action
  switch (type) {
    case 'add':
      return preState + data
    case 'reduce':
      return preState - data
    default:
      return preState
  }
}

store

将state、action、reducer联系在一起的对象

  1. 引入创建store的方法
    import {legacy_createStore as createStore} from 'redux'
    
  2. 引入创建好的reducer.js文件
    import reducer from './reducers'
    
  3. 使用并导出
    export default createStore(reducer)
    

异步action

异步action,就是指action的值为函数。

  1. redux默认是不能进行异步处理的
  2. 某些时候应用中需要在redux 中执行异步任务(ajax, 定时器)

利用中间插件

需要配合中间插件,不然会报错。

  1. 下载

    yarn add redux-thunk
    
  2. 引入

    import thunk from 'redux-thunk'
    
  3. 引入redux的中间件方法

    import {applyMiddleware} from 'redux'
    
  4. 暴露store中使用

    export default createStore(myReducer, applyMiddleware(thunk))
    
  5. 监听变化

    和通过 this.setState 一样,需要通过 subscribe 监听redux的内容的变化,否则不起效果。而这个检测可以写在入口文件 index.js 中。

    import store from '@/redux/store'
    
    store.subscribe(() => {
        ReactDom.render(<App />, doucment.getElementById('root'))
    })
    

React-Redux

两大类组件

  1. UI组件
    • 只负责 UI 的呈现,不带有任何业务逻辑
    • 通过props接收数据(一般数据和函数)
    • 不使用任何 Redux 的 API
    • 一般保存在components文件夹下
  2. 容器组件
    • 负责管理数据和业务逻辑,不负责UI的呈现
    • 使用 Redux 的 API
    • 一般保存在containers文件夹下

引用

  1. 下载

    yarn add react-redux
    
  2. 引入ui组件

    containers/ui/index.jsx 文件中引入

    import ui from '@/components/ui'
    
  3. 引入redux

    import store from '@/redux/store'
    

    这种引入方式是错误的,运行之后页面会报错,显示找不到store,需要在 App.js 中引入。

    import Ui from '@/containers/ui'
    import store from '@/redux/store'
    render() {
        return (
            <div>
                <Ui store={store}></Ui>
            </div>
        )
    }
    
  4. 引入connect用于连接ui组件与redux

    containers/ui/index.jsx 文件中引入

    import {connect} from 'react-redux'
    
    export default connect()(ui) // 使用connect()()创建一个容器组件并暴露出去
    

使用

a函数的返回值的对象中key作为传递给ui组件props的key,value作为传递ui组件props的value——状态。

通过 store.getState() 可以获取到初始值,但是这么写有问题。目前我们在容器组件内,一开始已经引入好了,函数a是通过 react-redux 调用的,可以直接使用 state 接收参数。

function a(state) {
    return {count: state}
}

b函数的返回值的对象中key作为传递给ui组件props的key,value作为传递ui组件props的value——操作状态的方法。

function b(dispatch) {
    return {
        add: (number) => dispatch({type:'add', data:number})
        reduce: (number) => dispatch({type:'reduce', data:number})
    }
}

把两个函数传过去。此时在ui组件中可以通过 this.props 获取到相应的数据。

export default connect(a, b)(ui)

注意:

函数不能这么取名,真正项目中应该取为 mapStateToPropsmapDispatchToProps

优化

简写connect

  1. 把state函数变为一个箭头函数,直接写在括号内。
  2. 把dispatch函数写成箭头函数,直接写在括号内。然后把函数改为一个对象的形式,直接调用action函数,根据函数名直接去调用原来的功能函数。
import { createAdd } from '@/redux/action'
export default connect(
    state => ({count:state}),
    {
        add: createAdd
    }
)(ui)

简化provider

  1. 容器组件会监听内容的变化,因此不再需要 subscribe 方法的检测,返回 index.js 文件中删除即可。
  2. 容器组件曾通过 store={store} 传递,但是如果容器组件一多,就要一遍一遍地写,很繁琐。解决方法:找到 App.js 的上一层,也就是 index.js 文件,在这里引入。
    import store from '@/redux/store'
    import Provider from 'react-redux'
    
    ReactDom.render(
        <Provider store={store}>
            <App/>
        </Provider>, 
        document.getElementById('root'))
    

组合组件

把ui组件和容器组件结合起来在一个文件中。

共享状态

创建多个 redux 组件时,要在store.js文件中引入暴露,但是不能同时多个暴露,会报错,此时需要用到 redux 中的 combineReducers 方法,传入的对象是redux保存的总状态对象。

import {createStore, applyMiddleware, combineReducers} from 'redux'
import thunk from 'react-thunk' // 异步action

const allReducer = combineReducers({
    count: countReducer,
    person: personReducer
})

export default createStore(allReducer, applyMiddleware(thunk))