乐趣区

关于react.js:React的5种高级模式

本文概述了 5 种古代高级 React 模式,包含集成代码、长处和毛病,以及在公共库中的具体用法。

像每个 React 开发者一样,你可能曾经问过本人以下问题之一

  • 我如何建设一个 可重复使用 的组件以适应不同的应用状况?
  • 我如何建设一个具备 简略 API的组件,使其易于应用?
  • 我如何建设一个在用户界面和性能方面 可扩大 的组件?

这些重复呈现的问题催生了整个 React 社区的一些高级模式的呈现

在这篇文章中,咱们将看到 5 种不同模式的概述。为了便于比拟,咱们将对所有这些模式应用一个雷同的构造。

咱们将从一个小的介绍开始,而后是一个实在的代码例子(基于同一个简略的 Counter 组件)。

咱们将列出长处和毛病,而后在一个名为 “ 规范 ” 的局部中定义两个因素。

  • 反转管制: 你的组件给用户提供的灵活性和管制等级
  • 施行的复杂性: 你和用户实现该模式的难度。

最初,咱们将找一些公共库在生产环境中应用该模式的例子

在这篇文章中,咱们将思考一个 React 开发者(你)为其余开发者构建一个组件的状况。因而,” 用户 ” 这个角色间接指的是这些开发者(而不是应用你的网站 / 应用程序的最终用户)。

1. 复合组件模式(Compound Components Pattern)

这种模式容许创立富裕表现力和申明性的组件,防止非必要的 prop drilling。如果你想让你的组件更有可塑性,有更好的关注点拆散和易了解的 API,你应该思考应用这种模式。

例子

import React from "react";
import {Counter} from "./Counter";

function Usage() {const handleChangeCounter = (count) => {console.log("count", count);
  };

  return (<Counter onChange={handleChangeCounter}>
      <Counter.Decrement icon="minus" />
      <Counter.Label>Counter</Counter.Label>
      <Counter.Count max={10} />
      <Counter.Increment icon="plus" />
    </Counter>
  );
}

export {Usage};

长处

  • 缩小了 API 的复杂性:与其把所有的 props 都塞进一个微小的父组件中,而后再把这些 props 钻到子 UI 组件中,不如在这里把每个 props 都连贯到各自最有意义的子组件上。
  • 灵便的标记构造:你的组件有很大的 UI 灵活性,容许从一个繁多的组件创立各种状况。例如,用户能够扭转子组件的程序或定义哪个组件应该被显示。
  • 关注点拆散:大部分的逻辑都蕴含在主 Counter 组件中,而后用 React.Context 来分享所有子组件的状态和事件处理。咱们失去了一个明确的责任划分。

毛病

  • 太高的 UI 灵活性:领有灵活性的同时,也有可能引发意想不到的行为(把一个不须要的组件的子组件放进去,把子组件的程序弄乱,遗记蕴含一个必须的子组件)

    依据你想要用户如何应用你的组件,你可能不心愿有那么多的灵活性。

  • 更重的 JSX:利用这种模式会减少 JSX 行的数量,特地是当你应用像 ESLint 这样的代码检测工具或相似 Prettier 这样的代码格式化工具时
    在单个组件的规模上,这仿佛不是什么大问题,但当你从全局来看时,必定会产生微小的差别。

规范

  • 反转管制:1/4
  • 施行的复杂性:1/4

应用此模式的公共库

  • React Bootstrap
  • Reach UI

2. 受控属性模式

这种模式将你的组件转变为一个受控组件。内部状态作为 “ 繁多事实源 “ 被耗费,容许用户插入自定义逻辑,批改默认组件的行为。

例子

import React, {useState} from "react";
import {Counter} from "./Counter";

function Usage() {const [count, setCount] = useState(0);

  const handleChangeCounter = (newCount) => {setCount(newCount);
  };
  return (<Counter value={count} onChange={handleChangeCounter}>
      <Counter.Decrement icon={"minus"} />
      <Counter.Label>Counter</Counter.Label>
      <Counter.Count max={10} />
      <Counter.Increment icon={"plus"} />
    </Counter>
  );
}

export {Usage};

长处

  • 给予更多的管制:因为主状态裸露在你的组件之外,用户能够管制它,因而能够间接影响你的组件。

毛病

  • 施行的复杂性: 之前,在一个中央(JSX)的一个集成就足以使你的组件工作。当初,它将扩散在 3 个不同的中央(JSX / useState / handleChange)。

    参考 React 实战视频解说:进入学习

规范

  • 反转管制:2/4
  • 施行的复杂性:1/4

应用此模式的公共库

  • Material UI

3. 自定义钩子模式

让咱们在 “ 管制反转 “ 中更进一步:次要的逻辑当初被转移到一个自定义的钩子中。这个钩子能够被用户拜访,并且裸露了几个外部逻辑(状态、处理程序),容许他对你的组件有更好的管制。

例子

import React from "react";
import {Counter} from "./Counter";
import {useCounter} from "./useCounter";

function Usage() {const { count, handleIncrement, handleDecrement} = useCounter(0);
  const MAX_COUNT = 10;

  const handleClickIncrement = () => {
    //Put your custom logic
    if (count < MAX_COUNT) {handleIncrement();
    }
  };

  return (
    <>
      <Counter value={count}>
        <Counter.Decrement
          icon={"minus"}          onClick={handleDecrement}
          disabled={count === 0}
        />
        <Counter.Label>Counter</Counter.Label>
        <Counter.Count />
        <Counter.Increment
          icon={"plus"}          onClick={handleClickIncrement}
          disabled={count === MAX_COUNT}
        />
      </Counter>
      <button onClick={handleClickIncrement} disabled={count === MAX_COUNT}>
        Custom increment btn 1      </button>
    </>
  );
}

export {Usage};

长处

  • 给予更多的管制: 用户能够在钩子和 JSX 元素之间插入本人的逻辑,容许他批改默认组件的行为。

毛病

  • 施行的复杂性:因为逻辑局部与渲染局部是离开的,所以必须由用户将两者分割起来。要正确地实现它,须要对你的组件的工作形式有一个很好的了解。

规范

  • 反转管制:2/4
  • 施行的复杂性:2/4

应用此模式的公共库

  • React table
  • React hook form

4. Props getter 模式

自定义钩子模式提供了很好的管制,但也使你的组件更难集成,因为用户必须解决大量的组件本地钩子的 props,并在他那边从新创立逻辑。Props Getters 模式试图覆盖这种复杂性。咱们不裸露本地props,而是提供一个props getters 的短名单。一个getter 是一个返回许多 props 的函数,它有一个有意义的名字,容许用户天然地将其链接到正确的 JSX 元素。

例子

import React from "react";
import {Counter} from "./Counter";
import {useCounter} from "./useCounter";

const MAX_COUNT = 10;

function Usage() {
  const {
    count,
    getCounterProps,
    getIncrementProps,
    getDecrementProps
  } = useCounter({
    initial: 0,
    max: MAX_COUNT
  });

  const handleBtn1Clicked = () => {console.log("btn 1 clicked");
  };

  return (
    <>
      <Counter {...getCounterProps()}>
        <Counter.Decrement icon={"minus"} {...getDecrementProps()} />
        <Counter.Label>Counter</Counter.Label>
        <Counter.Count />
        <Counter.Increment icon={"plus"} {...getIncrementProps()} />
      </Counter>
      <button {...getIncrementProps({ onClick: handleBtn1Clicked})}>
        Custom increment btn 1      </button>
      <button {...getIncrementProps({ disabled: count > MAX_COUNT - 2})}>        Custom increment btn 2      </button>
    </>
  );
}

export {Usage};

长处

  • 易用性:提供一种简略的形式来整合你的组件,复杂性被暗藏起来,用户只需将正确的 getter 连贯到正确的 JSX 元素。
  • 灵活性:用户依然有可能重载 getters 中的props,以适应他的具体情况。

毛病

  • 短少可见性:getters 带来的抽象性使你的组件更容易集成,但也更不通明和 “ 魔法 ”。为了正确地笼罩你的组件,用户必须晓得 getters 所裸露的 props 列表,以及如果其中一个 props 被扭转所带来的外部逻辑影响。

规范

  • 反转管制:3/4
  • 集成的复杂性:3/4

应用此模式的公共库

  • React table
  • Downshift

5. State reducer 模式

在管制的反转方面是最先进的模式。它为用户提供了一种先进的形式来扭转你的组件的外部操作形式。

代码相似于自定义钩子模式,但除此之外,用户还定义了一个被传递给钩子的 reducer。这个reducer 将重载你的组件的任何外部动作。

例子

    import React from "react";
    import {Counter} from "./Counter";
    import {useCounter} from "./useCounter";

    const MAX_COUNT = 10;
    function Usage() {const reducer = (state, action) => {switch (action.type) {
          case "decrement":
            return {count: Math.max(0, state.count - 2) //The decrement delta was changed for 2 (Default is 1)
            };
          default:
            return useCounter.reducer(state, action);
        }
      };

      const {count, handleDecrement, handleIncrement} = useCounter({ initial: 0, max: 10},
        reducer
      );

      return (
        <>
          <Counter value={count}>
            <Counter.Decrement icon={"minus"} onClick={handleDecrement} />
            <Counter.Label>Counter</Counter.Label>
            <Counter.Count />
            <Counter.Increment icon={"plus"} onClick={handleIncrement} />
          </Counter>
          <button onClick={handleIncrement} disabled={count === MAX_COUNT}>
            Custom increment btn 1          </button>
        </>
      );
    }

    export {Usage};

在这个例子中,咱们联合了 State reducer 模式和 Custom hook 模式,然而你也能够把它和 Compound components 模式一起应用,间接把 reducer 传递给主组件 Counter。

长处

  • 给予更多的管制:在最简单的状况下,应用 state reducers 是把控制权留给用户的最好办法。你所有的外部组件的动作当初都能够从内部拜访,并且能够被重写。

毛病

  • 施行的复杂性:这种模式的实现必定是最简单的,无论是对你还是对用户。
  • 短少可见性:因为任何 reducer 的动作都能够被扭转,因而须要很好地了解组件的外部逻辑。

规范

  • 反转管制:4/4
  • 集成的复杂性:4/4

应用此模式的公共库

  • Downshift

总结

通过这 5 个高级 React 模式,咱们看到了利用 “ 管制反转 “ 概念的不同形式。它们给你提供了一个弱小的办法来创立灵便和适应性强的组件。
然而,咱们都晓得这句驰名的谚语:” 能力越大责任越大 ”,你越是把控制权转移给用户,你的组件就越是远离 “ 即插即用 “ 的思维形式。作为一个开发者,你的角色是抉择正确的模式来对应正确的需要。
为了帮忙你实现这项工作,上面的图表依据 “ 集成的复杂性 “ 和 “ 管制反转 “ 这两个因素对所有这些模式进行了分类。

退出移动版