[React 进阶系列] 组成与继承
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[React 进阶系列] 组成与继承相关的知识,希望对你有一定的参考价值。
[React 进阶系列] 组成与继承
组成(Composition) 与 继承(Inheritance) 是两种比较常用的代码复用方案。
继承
传统的 OOP 语言之中继承的用法较多,如比较传统的动物案例:
继承就代表子类具有父类的所有特征,如哺乳类、爬行类都属于有脊椎动物,那么他们就一定会有脊椎。哺乳类属于恒温动物,犬科作为哺乳类的一员,自然也属于恒温动物。
继承是一个用的很好能够简化结构与实现的方案,但是对于结构与架构都非常有挑战的实现。稍一不小心就会尾大不掉,子类中可能继承过多不需要的特性,如:
这个设计就不是一个非常合理的设计,比较合理的设计应该让正方形直接继承形状。
通常情况下让正方形继承矩形不会有什么大问题,但是,如果有一个需求是让矩形的面积增加 10%这样一个需求,那么矩形就需要实现以下代码 [1]:
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
foreach(var rectangle in rectangles)
if (typeof(rectangle) == Rectangle)
rectangle.Length = rectangle.Length * 1.1;
if (typeof(rectangle) == Square)
rectangle.Length = rectangle.Length * 1.04880884817;
这时候的正方形已经不具备矩形所有的特性,强行让正方形继承矩形的意义也不大。
当然,不管继承怎么好或不好,React 官方团队的态度是:
We haven’t found any use cases where we would recommend creating component inheritance hierarchies.
即,他们到目前为止也没在 React 里面用上继承。
组成
React 文档中将组成分为了两个部分,容器化与特殊化。
容器化
组成是 React 所推荐的使用方法,在这种情况下,父组件不需要子组件的实现,只需负责将其渲染出来即可。最简单的例子是创建一个 Modal 组件,对于 Modal 组件来说,它并不需要在乎子组件会包含什么——可以是一个表单,可以是一段信息,又或者是其他根据需求需要渲染的内容。对于 Modal 而言,它需要实现的功能有两个:
- 将传递进来的子组件渲染出去
- 实现 Modal 的必要功能,如点击背景时关闭 Modal
这个时候使用继承就不是一个非常合适的方案,组成就是一个更加合适的方案。
Modal 的实现如下:
import useState from "react";
const Modal = ( show, children ) =>
const [isShown, setIsShown] = useState(show);
const closeModal = () =>
setIsShown(false);
;
if (!isShown)
return null;
return (
<div className="modal" onClick=closeModal>
children
</div>
);
;
export default Modal;
这个 Modal 实现了两个基础功能,点击“背景”时关闭 Modal,以及渲染传递进 Modal 的子组件。这个时候,作为父组件的 Modal 可以不需要在意子组件究竟是什么,只需要单纯将其渲染出去即可,如:
import StrictMode from "react";
import createRoot from "react-dom/client";
import "./styles.css";
import App from "./App";
import Modal from "./Modal";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<a href="">It's another message</a>
<Modal show=true>
/* 这个App里面就yiju hello,不过不管里面传递什么,Modal都能渲染出来 */
<App />
</Modal>
</StrictMode>
);
其渲染结果如下:
Modal 只是一个案例显示了组成的用途,其主要功能也是创建单独的最小子组件,尽最大程度的提升可复用性,减少重复代码。
特殊化
这种场景多运用于有些容器化的组件可能会被重复使用多次,依旧以上面的 Modal 为案例,假设业务需求是当用户需要注册时,不选择渲染一个单独的注册页面,而是跳出一个注册 Modal。而注册 Modal 应用的场景在于:用户主动点击注册按钮,没有帐户的用户再进行下载资源、阅读文章等操作时选择注册。这时候注册 Modal 就会在各个页面跳来跳去。
又因为注册只会出现在 Modal 中(这只是一个假设性的需求),所以根据同样的代码在项目中出现两次就需要封装的原则,这时候封装一个特殊化的注册 Modal 就是一个更好的选择。
RegisterModal 的实现大致如下:
const RegisterModal = () =>
// 省略表单之类的逻辑
return (
<Modal show=true>
<form>/* 省略注册表单的实现 */</form>
</Modal>
);
;
这样,当有用户通过点击事件打开 RegisterModal 时,开发者需要做的就是直接渲染 <RegisterModal />
即可。
参考
[1]: Why would Square inheriting from Rectangle be problematic if we override the SetWidth and SetHeight methods?
[2]: Composition vs Inheritance
以上是关于[React 进阶系列] 组成与继承的主要内容,如果未能解决你的问题,请参考以下文章
[React 进阶系列] Functional Component 与 Class Component 中使用 Context
[React 进阶系列] Functional Component 与 Class Component 中使用 Context