React 和TypeScript 练习笔记(二)—— 开发复合状态值的组件

本系列为Lemoncode开源项目(其中之一)练习总结,原项目共有15个练习,经分析,主要可归结为五个练习:

  • 1 简单交互与CP模式
  • 2 开发复合状态值的组件
  • 3 表格数据与后端缓存
  • 4 路由与表单验证
  • 5 Context与会话状态

第二组练习由7、8、9 三个子练习组成,目的归结起来主要为了展示

  • 开发复合交互状态值 (object)组件,和CP组件模式
  • 以及 children props 组件 API 的使用
07 ColorPicker
Simple color picker demo (show how properties work).
08 ColorPicker Refactor
09 Sidebar 
Implementation of a single sidebar.

复合状态值 的交互处理

本练习的重点,是复合交互状态(color{blue,red,green})的处理,复合值 在组件间传递会增加出错的概率,为了保证这种 处理 的低bug率,TypeScript 派上用场。用上TS保证安全,代码变得“繁盛”起来,学习和适用需要点时间。

组件功能

先从 了解 组件功能

1 调色组件功能

界面上有一色块组件(colorBrowser) ,它的值是复合的 由 color 状态保存,并有三个类似的调色控件(colorPicker) 调整 三原色的值(blue,red,green)。

这个功能 还是典型 CP模式实现,只是容器保存是 复合值color{blue,red,green},通过prop传递 和setState都要保证类型正确;另外,三个调色控件功能是相似,可以进一步抽象成通用组件复用,此为 professional 组件模式。

├── package.json
├── src 
│  ├── app.tsx // color 状态容器 
│  ├── components // 
│  │   ├── colorBrowser.tsx // color 状态展示组件(输出)
│  │   ├── colorPicker.tsx // color 状态展示组件(输入)
│  │   ├── index.tsx 
│  │   ├── sidebar.css
│  │   └── sidebar.tsx //
│  ├── index.html
│  ├── index.tsx
│  └── model // 前端 交互状态的数据模型
│    └── color.ts // 复杂交互状态的类型定义 
│── tsconfig.json 
└── webpack.config.js

2 弹出菜单的功能

此功能与前一个功能是不相关的,只是都使用了CSS。此功能主要为展示 children props组件 API,和CSS的使用。

功能非常简单,顶层容器组件有一个sidebar,开合由一个isVisible状态控制(由顶层组件 把持),isVisible有一个 Toggle 按键控制。

项目技术分析

第一,TypeScript 和Color 类型的使用

TypeScript 或强类型编程的意义可概括这样的一句话:大程序是被分割成模块的,模块之间存调用关系(进行分拆后的合并),当我们制作一通用模块(被调用模块)时要注意接口的类型,同样当我们调用(使用)这些模块功能 也要关心使用适当的类型。

有过C和JAVA背景的人会认为,所有符号都要声明类型,但TS只是JS的超集,没有声明的符号变量依然是合法TS代码,所以像一些类型很明显的地方可忽略类型声明,例如本地变量。

前端开发的 组件模块拆分 是常见,主要有专业分拆(例如CP模式组件),和复用拆分(例如 自定义HOOK)。例如如下 调色组件的 两个展示组件(ColorBrowser ColorPicker)的类型定义:

interface Color { red: number; green: number; blue: number;}
interface Props { color: Color;}
const ColorBrowser: React.FC<Props> = (props) => {}

interface Props { color: Color; onColorUpdated: (color: Color) => void;}
const ColorPicker: React.FC<Props> = (props) => ()

调用时需要使用适当的类型( 这里的color setColor 是 React.useState声明的)

<ColorBrowser color={color} />
<ColorPicker color={color} onColorUpdated={setColor} />

const [color, setColor] = React.useState<Color>({ red: 20, green: 40, blue: 180 });

第二,CSS的使用

界面CSS渲染,本练习只使用最简单的CSS技术

第三,components目录

为了整理 分拆的 组件,独立出一个components目录,index集中导出

项目代码简要分析

import {  ColorBrowser,  ColorPicker,  SidebarComponent} from "./components";
import { Color } from "./model/color";

export const App = () => {
  const [color, setColor] = React.useState<Color>({
    red: 20,
    green: 40,
    blue: 180
  });
  const [isVisible, setVisible] = React.useState(false);

  return (
    <>
      <SidebarComponent isVisible={isVisible}>
        <h1>Cool Scfi movies</h1>
        <ul>
          <li>
            <a href="https://www.imdb.com/title/tt0816692/">Interstellar</a>
          </li>
          <li>
            <a href="https://www.imdb.com/title/tt0083658/">Blade Runner</a>
          </li>
          <li>
            <a href="https://www.imdb.com/title/tt0062622/">
              2001: a space odyssey
            </a>
          </li>
        </ul>
      </SidebarComponent>
      <ColorBrowser color={color} />
      <ColorPicker color={color} onColorUpdated={setColor} />
      <div style={{ float: "right" }}>
        <button onClick={() => setVisible(!isVisible)}>Toggle Sidebar</button>
      </div>
    </>
  );
};
裸男
Nakeman.cn 2023 Build by Gatsby and Tailwind, Deploy on Netlify.