读react状态管理章有感

104 阅读6分钟

概要

  1. 表格的响应式写法(vue v-model(语法糖)的实现)

用state响应输入(告诉我们以下两点)

  • 声明式编程(面向对象编程),千万不要写面向过程的代码
  • 定义state的原则(尽量少的)
    1. 定义尽量少的state。
    2. 删除无用的state 例:状态相反的state,定义一个另一个取反 。
    3. 同一属性的多个状态,可以合并成一个state
    4. 一次想不好正常,react建议您重构state,尽可能让它最少

读 选择state结构 有感

  1. 没什么好说的,规范化state结构,给我们一些情况的优化方案(知道,有意识优化慢慢写出规范化优雅的react代码)
  2. 下面是具体规范
    • 如果两个 state 变量总是一起更新,请考虑将它们合并为一个。
    • 仔细选择你的 state 变量,以避免创建“极难处理”的 state。
    • 用一种减少出错更新的机会的方式来构建你的 state。
    • 避免冗余和重复的 state,这样您就不需要保持同步。
    • 除非您特别想防止更新,否则不要将 props 放入 state 中。
    • 对于选择类型的 UI 模式,请在 state 中保存 ID 或索引而不是对象本身。
    • 如果深度嵌套 state 更新很复杂,请尝试将其展开扁平化。
  3. 您还应该从“表”对象中删除已删除的项目(以及它们的子项!)以改善内存使用。还可以 使用 Immer 使更新逻辑更加简洁。

读 在组件中共享状态 有感

  1. 状态提升,把公共的状态提升到父组件中,
  2. 父子传值: 通过props传递给子组件使用,及传递事件处理程序以便子组件修改父组件状态
  3. 受控组件;可以被props驱动的组件,非受控被state驱动

读 对state保留和重置 有感 --- 主要告诉我们如何保留state状态

总结

  1. 保留和重置由两个因素决定,是否同一组件,是否同一ui位置
  2. 只有同一组件,同一位置才会被保留

强行重置(同一组件同一位置,state状态默认被保留,需求需要重置)

  1. 给组件添加key属性,重新渲染dom并且state会被重置, state单独保存和dom不在同一作用域

被移除的组件保留state(当我返回上一级,我想获取之前的state)

  1. 状态提升,把他放在父组件中,通过事件改变状态(通常用法)
  2. 隐藏使用css display
  3. 放在localStorage里面,进行状态持久化

Example

  1. 之前文章学过渲染同一个组件两次,每个副本都会有完全隔离的 state,用此解释是因为你渲染两次就是有上下级关系,在ui上来说位置肯定不同,所以state被重置,状态不会被保留。
  2. 代码例子重要,主要是第二个自己会歧义(总结下,不看逻辑,就看代码是否写在同一位置)
isShou? <Counter></Counter> : <Counter></Counter>; //被保留

// 被重置
{isPlayerA &&
        <Counter person="Taylor" />
      }
      {!isPlayerA &&
        <Counter person="Sarah" />
      }
      
1. 被重置解析
-   起初 `isPlayerA` 的值是 `true`。所以第一个位置包含了 `Counter` 的 state,而第二个位置是空的。
-   当你点击“下一位玩家”按钮时,第一个位置会被清空,而第二个位置现在包含了一个 `Counter`

读 迁移状态逻辑至reducer 有感

杂谈

  1. 核心概念好熟悉,vuex 或者 pnia用过?
  2. 为什么叫reducer(和js的方法重名),它们都接受 目前的状态action ,然后返回 下一个状态。这样,action 会随着时间推移累积到状态中。

目的

  1. 状态更新逻辑集中到同一函数(在思源,不想定义太多事件名称不是经常做吗)
  2. 触发类型定义在 action函数中

知识点 useReducer ---useImmerReducer

  • useReducer hook都可以定义state,相比于useState的setState 变成了dispath来触发action
  • useReducer定义的状态也可以使用immer修改---useImmerReducer
  • action概念
  • dispath 概念
  • ruducer与js的reducer入参相同,第一个参数回调函数(action对应的处理逻辑),第二个变量初始值

reducers必须是纯粹的

  1. 即当输入相同时,输出也是相同的
  2. 它们不应该包含异步请求、定时器或者任何副作用(对组件外部有影响的操作)
  3. 它们应该以不可变值的方式去更新 对象 和 数组。(和state一样的建议,把特们看作只读)
  4. 每个 action 都描述了一个单一的用户交互,即使它会引发数据的多个变化

Example

import {useReducer} from "react"
const [tasks, dispath]  =  useReducer(taskReducer, initTasks);

function taskReducer(stateData,action){
     switch (action.type) {
    case 'added': {
      stateData.push({
        id: action.id,
        text: action.text,
        done: false,
      });
      break;
    }
    case 'changed': {
      const index = stateData.findIndex((t) => t.id === action.task.id);
      draft[index] = action.task;
      break;
    }
    case 'deleted': {
      return stateData.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
   }
}

读 使用context深层次传递 有感--(轻便内置的状态管理工具)

  1. 轻便,内置在react中,学习成本低微小型应用的选择,减少依赖项
  2. redux更加全面的api,更加统一的设置,适合大型项目

知识点

  • createContext Hook --- 单独context.js文件创建Context--reateContext
  • useContext Hook --- use对应的context可以拿到context定义的默认值
  • createContext()实例的provide组件--- 提供了

createContext().provide --创建组件的provide组件

  1. 组件的value属性,可以为创建的实例,动态的传入值,最早的定义只是默认值
  2. provide组件,将会提供他的值,给到被他包裹的所有组件(递归的,直到无尽层)
  3. provide的值,由他刚创建时的初始值及,及组件的value属性控制,value优先级较大
  4. Example
1. context.js中创建context
import { createContext } from 'react';
export const LevelContext = createContext(1);


2. 父组件中使用LevelContext.provide组件提供LevelContext的值
import { LevelContext } from './LevelContext.js';
  // value控制LevelContext的值,没有则使用初始化的值,即context.js中的1
<LevelContext.Provider value={level}>  
 {children}  
</LevelContext.Provider>

3.子子孙孙组件中使用
import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

    // 注意Hook只能在顶层作用域中使用
    // 取最近的provide的值,没有就取默认值
const level = useContext(LevelContext);

最佳实践

  1. 使用context感觉也会出现,值的来源模糊的问题,provide提供的是初始化的值需要看代码,让维护变得没那么简单
  2. 官方推荐在使用 context之前,先看看嵌套是否太深,不深优先使用props这样state来源会更加新奇
  3. 抽象组件并 将 JSX 作为 children 传递 给它,具体:抽象出需要使用数据的功能,封装成组件,组件在靠近数据源的层级使用,然后通过默认插槽传递给需要使用的层级页面

推荐context使用的情况 --- 越看越像状态管理工具(有了context,为什么还要redux)

  1. 主题
  2. 当前账户
  3. 路由
  4. 状态管理 --reducer + context ---这个组合怎么有点像eventbus
  5. 总结就是全局状态的时候都建议使用context

兄弟组件中的传值 提一嘴

  1. 使用状态提升,把公用的属性提升到父组件进行保存

reducer + context结合

  1. 分别创建 state-context 和 dispatchcontext
  2. 通过 .provide 组件的value属性赋值,
  3. 返回该组件,通过child 默认插槽进行后代的提供

Example

import { createContext } from 'react';  
export const TasksContext = createContext(null);  
export const TasksDispatchContext = createContext(null);
export function TasksProvider({ children }) {  

const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);  
return (  
<TasksContext.Provider value={tasks}>  
<TasksDispatchContext.Provider value={dispatch}>  
{children}  
</TasksDispatchContext.Provider>  
</TasksContext.Provider>  
);  
}