Redux使用 ★★★

96 阅读4分钟

一、 Redux三大核心理念★★★

  • Store :定义数据state 只读
  • action :通过action来更新数据
  • reducer: 纯函数来执行修改

1.1 什么是 Redux Toolkit? ★★★

  • 官方推荐的编写 Redux 逻辑的方法。@reduxjs/toolkit 包封装了核心的 redux 包,包含我们认为构建 Redux 应用所必须的 API 方法和常用依赖。 Redux Toolkit 集成了我们建议的最佳实践,简化了大部分 Redux 任务,阻止了常见错误,并让编写 Redux 应用程序变得更容易
  • 要写任何的 Redux 逻辑,你都应该使用 Redux Toolkit 来编写代码
  • 创建 Redux Toolkit 来消除手写 Redux 逻辑中的「样板代码」,防止常见错误,并提供简化标准 Redux 任务的 API
  • 创建 Redux Toolkit 来消除手写 Redux 逻辑中的「样板代码」,防止常见错误,并提供简化标准 Redux 任务的 API

1.2 redux基本使用

  • 使用npm install redux 安装redux

简单基本示例使用

Eg:

//store.js
// 进行引入
const { createStore } = require("redux")

// 定义初始化数据
const initState = {
 name: "林夕",
 age: 18
}
// 定义reducer函数:纯函数
function reducer(state = initState, action) {
 // 参数state:store目前保存的state
 // 参数action:本次次需要更新Waction(dispatchi入iaction)
 // console.log(state, action);
 // 有数据更新进行更新,返回新state
 switch (action.type) {
   case "name_change":
     return { ...state, name: action.name }
   case "age_change":
     return { ...state, age: action.age }
   default:
     return state;
 }


 // 返回值就是本次存储的initState值:即store值
 return state
}
// 创建store
const store = createStore(reducer)

module.exports = store
//使用
const store = require("./store");
console.log(store.getState());


// 修改store中的数据:必须action
const nameAction = { type: 'name_change', name: 'Go to swimming pool' }
store.dispatch(nameAction)
console.log(store.getState());
const ageAction = { type: 'age_change', age: 22 }
store.dispatch(ageAction)
console.log(store.getState());

逐步优化代码,监听订阅修改使用subscribe

1.3 subscribe(listener)监听数据是否变化

变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state

1.3.1 参数

  1. listener (Function): 每当 dispatch action 的时候都会执行的回调。state 树中的一部分可能已经变化。你可以在回调函数里调用getState() 来拿到当前 state。store 的 reducer 应该是纯函数,因此你可能需要对 state 树中的引用做深度比较来确定它的值是否有变化。

1.3.2返回值

(Function): 一个可以解绑变化监听器的函数。

const store = require("./store");

// 定义动态生成action可以新建新文件---始
//这里的type名字同样可以进行抽取使用。
const nameActionDispatch = (name) => ({ type: "name_change", name })
const ageActionDispatch = (age) => ({ type: "age_change", age })
// 定义动态生成action可以新建新文件---末

//订阅监听 
const unsubscribe = store.subscribe(() => {
  console.log("监听修改", store.getState());
})

// 修改store中的数据:必须action
store.dispatch(nameActionDispatch("Go to swimming pool"))
store.dispatch(ageActionDispatch(22))
//取消订阅监听
unsubscribe()
store.dispatch(nameActionDispatch("取消订阅"))
  • 其上代码我们可以进行拆分逻辑抽取单独文件进行优化,做到编写一次复用N次进行优化。
  • 同时遵从三大核心理念进行拆分文件,有需要可以拆分一个常量文件用来导出type名;

tips

  • 注意:node中对ES6模块化的支持
  • 从node v13.2.0开始,node才对ES6模块化提供了支持
  • node v13.2.0之前,需要进行如下操作:
    • 在package.json中添加属性:"type":"module”;
    • 在执行命令中添加如下选项:node --experimental-modules src/index.js;
    • node v13.2.0之后,只需要进行如下操作:在package.json中添加属性:"type":"module”;
  • 注意:导入文件时,需要跟上.js后缀名:

二、 react中初次使用redux实例练习

  • 使用create-react-app '项目名' 创建项目
  • 使用npm install redux 安装redux

示例效果

result.gif

新建目录

image.png

APP.jsx文件

import React, { PureComponent } from 'react'
import Home from './peages/Home'
import User from './peages/User'
import { HOC } from './utils/higherOrderComponent'

const Homes = HOC(Home)
const Users = HOC(User)

// 这里懒得拆分单文件了,使用函数创建了一个组件
const Header = HOC((props)=>{
  return(<h2>我是APP组件:{props.count}</h2>)
})

export class App extends PureComponent {
  render() {
    return (

      <>
        <Header/>
        <Homes />
        <div>
          <Users />
        </div>
      </>
    )
  }
}

export default App

Home.jsx文件子组件

import React, { PureComponent } from 'react'
import store from '../store'
import { addNumAction } from '../store/actionCreators'

export class Home extends PureComponent {
  add(num){
    store.dispatch(addNumAction(num))
  }
  render() {
    //高阶组件进行拦截后的传输参数
    const { count } = this.props
    return (
      <>
        我是home增加计数:{ count }
        <div>
          <button onClick={e=>this.add(1)}>+1</button>
          <button onClick={e=>this.add(5)}>+5</button>
          <button onClick={e=>this.add(10)}>+10</button>
        </div>
      </>
    )
  }
}

export default Home

User.jsx文件子组件

import React, { PureComponent } from 'react'
import store from '../store'
import { reduceNumAction } from '../store/actionCreators'

export class User extends PureComponent {
  reduceClick(num) {
    store.dispatch(reduceNumAction(num))
  }
  render() {
    //高阶组件进行拦截后的传输参数
    const { count } = this.props
    return (
      <>
        我是User减少计数:{count}
        <div>
          <button onClick={e => this.reduceClick(1)}>-1</button>
          <button onClick={e => this.reduceClick(5)}>-5</button>
          <button onClick={e => this.reduceClick(10)}>-10</button>
        </div>
      </>
    )
  }
}

export default User

higherOrderComponent.js高阶组件不明白高阶组件的使用请移步React的高阶组件

import {PureComponent} from 'react'
import store from '../store'
// 这里封装了一个高阶组件,相当进行拦截操作。
export function HOC(WrappedComponent){
  class NewWrappedComponent extends PureComponent{
    constructor() {
      super()
      this.state = {
        count:store.getState().counter
      }
    }
    componentDidMount() {
      store.subscribe(() => {
        const state = store.getState()
        //实现更新因为这里高阶组件使用setState数据变化都会进行更新界面
        this.setState({count:state.counter})
      })
    }
    render(){
      return(
        <>
          <WrappedComponent {...this.props} {...this.state}/>
        </>
      )
    }
  }
  return NewWrappedComponent
}

2.1 redux结构划分

源自coderwhy学习

store/index.js入口文件

import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)

export default store

reducer.js 纯函数来执行修改state

import { ADD_COUNTER, REDUCE_COUNTER } from './constants'

const initState = {
  counter: 10
}

function reducer(state = initState, action) {
  switch (action.type) {
    case ADD_COUNTER:
      let counter = state.counter + action.counter
      return { ...state, counter }
    case REDUCE_COUNTER:
      let reduceCounter = state.counter - action.counter
      return { ...state, counter: reduceCounter }
    default:
      return state;
  }
}

export default reducer

actionCreators.js执行action函数抽取单文件

import { ADD_COUNTER,REDUCE_COUNTER } from './constants'
export const addNumAction = (counter) => ({ type: ADD_COUNTER, counter })
export const reduceNumAction = (counter) => ({ type: REDUCE_COUNTER, counter })

constants.js 用来存储改type

export const ADD_COUNTER = "add_counter"
export const REDUCE_COUNTER = "reduce_counter"

连接下文

未完待续。。。