React之Redux用法(一)

Redux

  • Redux是将整个应用状态存储到store,store里存在一个状态树state tree
  • 组件可通过store.dispatch派发行为action给store,store不会直接修改state,而是通过用户编写的reducer来生成新的state,并返回给store
  • 其他组件通过订阅store中的state状态来刷新试图

在这里插入图片描述

注意点:

  • 整个应用有且只有一个store,其内部的state tree存储整个应用的state
  • state是只读的,修改state只能通过派发action,需要通过reducer纯函数描述action如何修改state的
  • 单一数据源的设计让React组件之间通信更加方便,也有利于状态的统一管理

先看一个计数器的例子:
store.js

import {
    
    createStore} from 'redux'

export const ADD = 'ADD'
export const MINUS = 'MINUS'

const reducer = (state = {
     
     count:0}, action) => {
    
    
    console.log('action', action)
    switch(action.type){
    
    
        case ADD:
            return {
    
    count: state.count + 1}
        case MINUS:
            return {
    
    count: state.count - 1}
        default:
            return state
    }
}

let store = createStore(reducer)
export default store

1.关于store

通过createStore可以创建一个store,方法里需要传入参数reducer。创建的store是一个对象,有以下方法可以调用:

  • store.getState(): 获取最新的state tree
  • store.dispatch(): 派发行为action
  • store.subscribe(): 订阅store中state的变化

2.关于reducer

reducer必须是个纯函数,接收state和action。state是旧状态,根据action.type的不同,生成新的state并返回
Counter.jsx

import {
    
     useEffect, useState } from 'react'
import store from './store'

const Counter = () => {
    
    
    //通过getState方法获取count值
    const [num, setNum] = useState(store.getState().count)
   
    useEffect(()=>{
    
    
        //通过subscribe实现订阅,当store中state状态发生变化时,就将新值传入
        const unSubscribe = store.subscribe(()=>{
    
    
           setNum(store.getState().count)
        }) 
        return () => {
    
    
            //取消订阅
            unSubscribe && unSubscribe()
        }
    },[])

    return (
        <div>
            <p>{
    
    num}</p>
            //通过dispatch派发action给store
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'ADD'})}}>+</button>
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'MINUS'})}}>-</button>
        </div>
    )
}

export default Counter

这样一个简单的Counter组件就实现了。在这里插入图片描述
Redux内部就是使用了’发布-订阅’模式。

3.combineReducers

当一个应用中包含多个模块,将所有模块的state放在一起并不合理,更好的做法是按照模块进行划分,每个模块都有自己的reducer和action,最终通过Redux的combineReducers合并成一个大的reducer。
combineReducers方法接收一个对象,属性key可任意设置,value对应每个模块的reducer函数,最终返回一个合并之后的reducer方法。

import {
    
    createStore, combineReducers} from 'redux'

export const ADD = 'ADD'
export const MINUS = 'MINUS'
export const SUM_ADD = 'SUM_ADD'
export const SUM_MINUS = 'SUM_MINUS'

const countReducer = (state = {
     
     count:0}, action) => {
    
    
    console.log('action', action)
    switch(action.type){
    
    
        case ADD:
            return {
    
    count: state.count + 1}
        case MINUS:
            return {
    
    count: state.count - 1}
        default:
            return state
    }
}

const sumReducer = (state = {
     
     sum:0}, action) => {
    
    
    console.log('action', action)
    switch(action.type){
    
    
        case SUM_ADD:
            return {
    
    sum: state.sum + 1}
        case SUM_MINUS:
            return {
    
    sum: state.sum - 1}
        default:
            return state
    }
}

const combineRe = combineReducers({
    
    countReducer, sumReducer})
let store = createStore(combineRe)
export default store
import {
    
     useEffect, useState } from 'react'
import store from './store'

const Counter = () => {
    
    
    //注意这里的取值
    const [num, setNum] = useState(store.getState().countReducer.count)
    const [sum, setSum] = useState(store.getState().sumReducer.sum)
   
    useEffect(()=>{
    
    
        const unSubscribe = store.subscribe(()=>{
    
    
           setNum(store.getState().countReducer.count)
           setSum(store.getState().sumReducer.sum)
        }) 
        return () => {
    
    
            unSubscribe && unSubscribe()
        }
    },[])

    return (
        <div>
            <p>{
    
    num}</p>
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'ADD'})}}>+</button>
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'MINUS'})}}>-</button>

            <p>{
    
    sum}</p>
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'SUM_ADD'})}}>+</button>
            <button onClick={
    
    ()=>{
    
    store.dispatch({
    
    type: 'SUM_MINUS'})}}>-</button>
        </div>
    )
}

export default Counter

如果在store.js中我们这样设置combineReducers:

const combineRe = combineReducers({
    
    
    a:countReducer, 
    b:sumReducer
})

那么在接下来的组件获取值时就应该这么用:

store.getState().a.count
store.getState().b.sum

reducer合并之后,store中的state tree也会按照模块进行划分。
当组件中派发action时,action会传递到combineReducers返回的函数中,在该函数中,会调用每个模块各自的reducer生成各自新的state, 最终将所有state合并之后,去更新store中的state。

总结

在React组件中使用store,需要手动引入store文件,手动订阅store中状态的变化,这样并不合理,所以我们需要引入react-redux来解决问题。

猜你喜欢

转载自blog.csdn.net/LittleMoon_lyy/article/details/124558910