学习目标:

  1. 掌握 Context 使用方法
  2. 掌握 Reducer 使用方法
  3. 掌握 Context 和 Reducer 结合使用方法

Context 的说明

在使用 Context 之前,先了解一下为什么会有 Context 的概念诞生。在 React 开发中,通过组件上下层级进行状态分享,比如通过父组件的 props 传递到子组件。但当组件数量增多,复杂度提升,嵌套比较多的情况下,从上至下的传递方式显得不便利,也不利于后期代码的调整和优化。当然,可以通过把公共状态提升至两个组件的同一父级来减少不必要的传递,但更好的一种方法可能就是使用 Context。 

Context,当在一个组件周围放置一个 Context,并提供需要共享的数据时,在 Context 以内的所有子组件都可以获取该状态,所有组件这个需要特别说明一下,就是不管距离近还是距离远的组件都可以接收到该状态,那也就说,嵌套更深的组件也可以一键获取。下面来看一下 Context 的使用与法。

Context 使用与法

1. 创建 Context

在一个独立模块文件里创建 Context

import { createContext } from "react";

export const MyContext = createContext(defaultValue);

这里命名稍微注意一下,一般首字母大写,createContext 里只接收一个参数,就是这个状态的初始值,如果需要有多个状态进行数据共享,则需要创建多个 Context。

2. 使用 Context

2.1 使用 useContext() 方法

 如果我想在组件里直接获取状态,比如有一个 side-effect 需要执行,则可以通过 useContext(MyContext) 获取 Context 的值。

import { MyContext } from './MyContext.js';

export default ChildrenComponent({children}) {
    const myState = useContext(MyContext);
}
2.2 使用 Provider 

如果我想在 DOM 中为 Context 赋值,并使孩子元素都能顺利获取该 Context,则通过 Provider 方法为 Context 赋值,注意的是,是通过 Context 的 Provider 为该 Context 赋值。

import { MyContext } from './MyContext.js';


export default function ParentComponent({data, children}) {
    return (
        <div className="parent-component">
           <MyContext.Provider value={data}>
               {children}
           <MyContext.Provider>
        </div>
    )
}

以上基本就是 Context 的使用方法,掌握了基本方法之后,结合实际业务场景,可以选择适合自己业务场景的方式使用。

那么下面来到 Reducer 环节。

Reducer 的基本概念

和 Context 对应状态值不同,Reducer 是对应事件方法。如果说可以用 Context 来替代 useState() 的话,Reducer 可以替代事件方法。

常见的一种情况是,我需要增删改查,但一般增删改查逻辑会很相似,如果单独写三个方法会显得冗余,这时可以使用 Reducer 的 dispatch 机制,通过定义事件的类型,行为模式和参数类型来响应对应事件。

比如我要增删一个数组,我可以这么定义

function addItem(item) {
    dispatch({
        type: 'add',
        data: item
    })
}

function removeItem(item) {
    dispatch({
        type: 'delete',
        data: item
    })
}

这里可以发现,我并没有去实现方法,而是定义方法,一般规定需要 type 来描述事件的类型,其余参数可根据业务需求进行增加。

那在定义好事件类型之后,我就要去执行事件。实际的执行方法则会放在 xxxReducer 的一个方法里。语法如下:

function operateItem(items, action) {

    if (action.type == 'add') {
        return [
            ...items,
            aciton.data 
        ]       
    }
    // 需要有新的返回值
}

这的方法第一个参数是我在更改前的数组,也就是常说的 prevData,action 是我定义的方法和传递的参数。这里值得注意的是,一般会有 swtich 来进行事件类型判断,毕竟事件数很多的情况下,首选 Reducer 处理复杂逻辑。

最后,我们申明 Reducer 的方法如下:

import { useReducer } from 'react';

const[state, dispatch] = useReducer(MyReducer, initialState);

其中 MyReducer 是实现方法的地方,也就是类似之前的 operateItem 方法,而 initialState 是我的初始状态值。比如如果我需要对一个 items 进行增删改,items 的初始值可以在这里传入。

掌握两者基本方法之后,我们看一下两者如何结合使用。

React 的 Reducer 和 Context 结合使用法

我们已经知道 Reducer 为方法而生,Context 辅助 useState,那两者的结合便是,让方法成为可流动的 state,也就是说所有孩子结点可以调用任一父级结点的方法。

语法和上面描述一致,需要注意的是,我的 dispatch 和我的 state 则放进 useContext(defaultValue)里。具体如下:

首先申明两个 Context:

import { crateContext } from 'react';

export const ItemContext = createContext(null);
export const ItemDispatchContext = createContext(null);

在 Reducer 的部分保持不变,因为我们事件类型和实现没有发生变化。

在 DOM 结构中,则需要 Provider 我们的两个 Context,实现如下:

import { ItemContext, ItemDispatchContext } from './ItemContext.js';
import { useReducer } from 'react';


export default function Parent() {
    const [items, dipatch] = useReducer(
        operateItem,
        initialItems
    )

    function addItem(item) {
        dispatch({
            type: 'add',
            data: item
        })
    }

    return (
        <ItemContext.Provider value={items}>
            <ItemDispatchContext.Provider value={dispatch}>
               <Children />
               <Children />
            </ItemDispatchContext.Provider>    
       </ItemContext.Provider>
    )
}

const initialItems = [
    { id: 0, name: 'apple' }, 
    { id: 1, name: 'banana' }
];

总结

以上就是 React 的 Context 和 Reducer 的学习之旅~咱们下期见~


更多推荐