状态管理 (react使用篇)

前言

在前端项目中,状态管理是一个非常重要的概念和技术。它用于管理应用程序的数据和状态,并确保不同组件之间的数据同步和一致性。趁抚摸fish的时间整理一下使用过的方案。。

Context API

使用 React 构建应用程序时,Context API 是一种用于在组件之间共享状态的机制。它允许你在组件树中传递数据,而不需要手动通过 props 一层层传递。Context API 在某些场景下可以作为全局状态管理的替代方案,尤其适用于较小规模的应用程序或对状态共享需求较简单的情况。

Context API 讲解

  1. 创建一个 Context组件(MyContext.js): 通过 createContext 函数来实现
js 复制代码
import React from 'react';

const MyContext = React.createContext();

export default MyContext;
  1. 提供数据: 接下来,你需要在组件树的某个位置提供数据,使得其他组件可以访问到这个数据。这通常在应用程序的根组件(App.js)中完成。你可以使用 Context.Provider 组件来提供数据,并将数据作为 value 属性传递给它。
js 复制代码
import React from 'react';
import MyContext from './MyContext';
import ChildComponent from './ChildComponent';

const data = { name: 'John', age: 25 };

function App() {
  return (
    <MyContext.Provider value={data}>
      <ChildComponent />
    </MyContext.Provider>
  );
}

export default App;
  1. 使用数据: 一旦您在组件树中提供了数据,其他组件就可以通过用 Context.ConsumeruseContext 钩子来访问该数据
  • 使用 Context.Consumer: 在类组件中,你可以使用 Context.Consumer 组件来访问提供的数据。它接受一个函数作为子元素,并将提供的数据作为该函数的参数。例如:

    js 复制代码
    class ChildComponent extends React.Component {
      render() {
        return (
          <MyContext.Consumer>
            {data => <div>{data.name}</div>}
          </MyContext.Consumer>
        );
      }
    }
  • 使用 useContext 钩子: 在函数式组件中,你可以使用 useContext 钩子来访问提供的数据。它接受一个 Context 对象作为参数,并返回当前提供的值。例如:

    js 复制代码
    function ChildComponent() {
      const data = React.useContext(MyContext);
      return <div>{data.name}</div>;
    }

在上面的示例中,ChildComponent 组件可以访问到通过 MyContext.Provider 提供的数据,并在组件中使用它。

Redux

Redux 是一个独立的状态管理库。Redux 的核心概念是单一的全局状态树,通过定义 action、reducer 和 store,可以实现可预测的应用程序状态,通过使用纯函数来管理状态的变化。

Redux讲解

三大核心原则

Redux 遵循以下三个核心原则:

  • 单一数据源:整个应用的状态被存储在一个单一的 JavaScript 对象中,称为"state"。
  • 状态是只读的:唯一改变状态的方式是通过触发一个"action",一个描述发生什么事件的普通 JavaScript 对象。
  • 使用纯函数来执行状态修改:使用"reducers",纯函数,根据当前状态和一个 action 来计算新的状态。

核心概念

  • Store:Redux 的状态存储库,用于存储应用的整个状态树。
  • State:应用的状态,存储在 Store 中。
  • Action :描述发生事件的普通 JavaScript 对象,包含一个type字段和其他自定义字段。
  • Reducer:纯函数,接收当前状态和一个 action,返回一个新的状态。Reducers 用于根据 action 更新状态。
  • Dispatch :通过调用store.dispatch(action)来触发一个 action,并将其传递给 reducer。
  • Subscribe :通过调用store.subscribe(listener)来注册一个监听器,当状态改变时会被调用。

数据流

Redux 的数据流是单向的,遵循以下顺序:

  1. 调用store.dispatch(action)来触发一个 action。
  2. Redux 调用注册的 reducers,并将当前状态和 action 传递给它们。
  3. Reducers 根据 action 的类型来更新状态,并返回一个新的状态。
  4. Redux 更新存储在 Store 中的状态。
  5. 如果有注册监听器,Redux 调用它们,以便通知状态的改变。
  6. 用户界面根据新的状态进行更新。

代码示例( Redux Toolkit)

Redux Toolkit 是为了简化和提高 Redux 开发体验而设计的,并且尽可能减少样板代码的编写。它提供了一组工具和约定,使得编写和组织 Redux 代码更加简单和高效。

依赖

首先,确保已经安装了Redux和Redux Toolkit。可以使用以下命令进行安装:

sql 复制代码
npm install redux @reduxjs/toolkit --save

目录结构

markdown 复制代码
- src
  - counterSlice.js
  - index.js
  - App.js
  - components
    - Counter.js

counterSlice.js

使用createSlice函数创建了一个名为counter的Slice(Slice 是一个包含 reducer、action 和 action creator 的单个模块化单位)。name属性指定了Slice的名称,initialState属性设置了计数器的初始值为0。reducers对象定义了三个reducer函数:incrementdecrementincrementByAmount,用于增加、减少和按指定值增加计数器的值。

然后,导出了这三个action creator函数:incrementdecrementincrementByAmount,以及reducer函数

js 复制代码
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment(state) {
      return state + 1;
    },
    decrement(state) {
      return state - 1;
    },
    incrementByAmount(state, action) {
      return state + action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

index.js

应用程序的主文件中, 导入了必要的依赖项,包括configureStore函数和Provider组件。然后,导入了之前创建的counterReducer,并将其作为counter键的值传递给configureStore函数,以创建Redux store。最后,使用ReactDOM.render函数将App组件包装在Provider组件中,并将Redux store传递给Provider组件。

js 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import counterReducer from './counterSlice';
import App from './App';

const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

App.js

创建一个React组件文件,命名App.js,使用useSelector钩子从Redux store中选择计数器的值。然后,使用useDispatch钩子获取一个dispatch函数,以便可以触发Redux action。

接下来,定义了三个事件处理函数:handleIncrementhandleDecrementhandleIncrementByAmount,它们分别通过调度相应的Redux action来增加、减少和按指定值增加计数器的值。

最后,在组件的渲染部分显示了计数器的值,并为每个按钮添加了相应的点击事件。

js 复制代码
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';

function App() {
  const count = useSelector((state) => state.counter);
  const dispatch = useDispatch();

  const handleIncrement = () => {
    dispatch(increment());
  };

  const handleDecrement = () => {
    dispatch(decrement());
  };

  const handleIncrementByAmount = () => {
    dispatch(incrementByAmount(5)); // 可以传递任意增加的值
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
      <button onClick={handleDecrement}>Decrement</button>
      <button onClick={handleIncrementByAmount}>Increment by 5</button>
    </div>
  );
}

export default App;

umi框架实现

(其实Umi 推荐并内置了 Dva 提供了一套状态管理方案,我也试了下,哈哈哈。。)

content 高阶函数可以将 Redux 的状态和操作注入到组件中,使得组件可以方便地访问和操作 Redux 的数据。

通过使用 connect,你可以在组件中声明所需的状态和操作,而不需要手动编写订阅和分发逻辑。connect 会自动处理与 Redux 的交互,简化了 Redux 的使用过程,减少了代码的编写。

arduino 复制代码
import { connect } from 'umi';

src目录下的数据文件models文件下新建一个counter.js文件

js 复制代码
const CounterModel = {
  state: {
    count: 0,
  },
  reducers: {
    increment(state) {
      return { ...state, count: state.count + 1 };
    },
    decrement(state) {
      return { ...state, count: state.count - 1 };
    },
    incrementByAmount(state, payload) {
      return { ...state, count: state.count + payload.num };
    },
  },
};

export default CounterModel;

在你使用的组件里按如下使用

js 复制代码
import React from 'react';
import { connect } from 'umi';

function Counter({ count, dispatch } :any) {
  const handleIncrement = () => {
    dispatch({ type: 'counter/increment' });
  };

  const handleDecrement = () => {
    dispatch({ type: 'counter/decrement' });
  };

  const handleIncrementByAmount = () => {
    dispatch({ type: 'counter/incrementByAmount', num: 5 }); // 可以传递任意增加的值
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
      <button onClick={handleDecrement}>Decrement</button>
      <button onClick={handleIncrementByAmount}>Increment by 5</button>
    </div>
  );
}

export default connect(({ counter }: any) => ({ count: counter.count }))(Counter);

MobX

MobX是一个简单、可扩展和高效的状态管理库,它使用观察者模式来跟踪状态的变化并自动更新相关的组件

Mobx讲解

核心概念

MobX 的核心概念包括以下几个关键点:

  1. 可观察数据(Observable) :可观察数据是 MobX 的基础概念之一。可观察数据是指被标记为可观察的状态,当这些数据发生变化时,MobX 将自动追踪并通知相关的观察者。在 MobX 中,可以使用 observable 装饰器或 observable 函数来定义可观察数据。
  2. 动作(Actions) :动作是一种更改可观察数据的操作。在 MobX 中,使用 action 装饰器或 action 函数来标记方法为动作。当动作被调用时,MobX 将跟踪该动作对可观察数据的修改,并确保触发相应的更新。
  3. 观察者(Observer) :观察者是指订阅可观察数据变化的组件或函数。在 MobX 中,可以使用 observer 函数或 @observer 装饰器将组件转换为观察者组件。观察者会自动订阅可观察数据的变化,并在数据发生变化时自动重新渲染。
  4. 自动追踪(Auto-tracking) :自动追踪是 MobX 的一个重要特性。当可观察数据被访问时,MobX 将自动追踪数据的依赖关系,并建立观察者与可观察数据之间的连接。这意味着当数据发生变化时,相关的观察者将自动被通知和更新。
  5. 衍生数据(Computed) :衍生数据是根据可观察数据计算得出的数据。在 MobX 中,可以使用 computed 装饰器或 computed 函数来定义衍生数据。衍生数据具有自动缓存和惰性计算的特性,只有在相关的可观察数据发生变化时才会重新计算。

数据流

在 MobX 中,数据流遵循以下基本流程:

  1. 定义可观察数据(Observable Data) :通过使用 observable 装饰器或 observable 函数,我们可以将数据标记为可观察的。这意味着当数据发生变化时,MobX 将自动追踪这些变化。
  2. 定义动作(Actions) :通过使用 action 装饰器或 action 函数,我们可以将方法标记为动作。动作是一种更改状态的操作,它们可以修改可观察数据。
  3. 创建观察者组件(Observer Components) :通过使用 observer 函数或 @observer 装饰器,我们可以将 React 组件转换为观察者组件。观察者组件订阅了可观察数据的变化,并在数据发生变化时自动重新渲染。
  4. 自动追踪数据变化(Automatic Tracking) :一旦数据发生变化,MobX 将自动追踪和记录数据的变化。这意味着任何观察者组件订阅的数据将自动更新,并进行相应的重新渲染。
  5. 通知观察者(Observer Notification) :当数据发生变化时,MobX 将自动通知所有相关的观察者组件。这样,观察者组件就能够根据新的数据进行更新和渲染。

代码示例

依赖

首先,确保已经安装了mobx mobx-react。可以使用以下命令进行安装

bash 复制代码
npm install mobx mobx-react --save

目录结构

在这个目录结构中,src 是源代码根目录,components 目录用于存放应用程序的组件,stores 目录用于存放 MobX 的状态管理类

css 复制代码
src/
  |- components/
  |    |- Counter.js
  |
  |- stores/
       |- CounterStore.js

CounterStore.js

这是一个 MobX 的状态管理类文件,负责定义和管理计数器的状态和行为

js 复制代码
import { observable, action } from 'mobx';

class CounterStore {
  @observable count = 0;

  @action increment() {
    this.count++;
  }

  @action decrement() {
    this.count--;
  }
}

const counterStore = new CounterStore();
export default counterStore;

Counter.js

这是一个 React 组件文件,负责渲染计数器界面和处理用户操作。它使用 MobX 的状态管理类来获取和更新计数器的值

js 复制代码
import React from 'react';
import { observer } from 'mobx-react';
import counterStore from '../stores/CounterStore';

const Counter = observer(() => {
  return (
    <div>
      <h2>Count: {counterStore.count}</h2>
      <button onClick={counterStore.increment}>Increment</button>
      <button onClick={counterStore.decrement}>Decrement</button>
    </div>
  );
});

export default Counter;
相关推荐
Marry1.03 分钟前
uniapp背景图用本地图片
前端·uni-app
夏河始溢9 分钟前
一七八、Node.js PM2使用介绍
前端·javascript·node.js·pm2
记忆深处的声音10 分钟前
vue2 + Element-ui 二次封装 Table 组件,打造通用业务表格
前端·vue.js·代码规范
陈随易10 分钟前
兔小巢收费引发的论坛调研Node和Deno有感
前端·后端·程序员
熊的猫25 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn32 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie2 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust2 小时前
css:基础
前端·css