Press "Enter" to skip to content

React 和TypeScript 练习笔记(一)——简单交互与CP模式

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

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

第一个练习由前6 个子练习组成,目的归结起来主要为了展示 最经典的React 组件模式——CP模式。

00 Boiler plate
01 Hello React
02 Properties
03 State
04 Callback
05 Refactor
06 Enable

CP模式

CP模式就是 Container-Presenter模式(容器与展示组件模式)。前端开发中最常见的任务莫过于 组件的粒度的设计,就是 将一个大组件分拆为多个子组件的最佳实践。例如 “应该将状态放在组件树的哪里最合适?”,“lifting state up” 就是社区的一种经验见解,其实本质是 Container-Presenter模式。

Container-Presenter模式 是种 父子关系的组件结构,父组件是一个容器组件,负责初始化交互状态,保持交互状态,和定义操作状态的逻辑(一般是交互事件处理,也不尽然); 子组件 是一展示型组件,负责交互输出——将交互结果(状态)渲染出来,也负责接受用户交互输入。

由于被分割了,组合它们是靠React props技术,包括data props 和 callback props。

项目功能

练习项目的交互功能 非常的简单,就是 用一个输入框接受用户的键盘输入,点击界面按键(鼠标输入)后 更新状态输出来,没有任何处理。

项目技术遗漏

本练习项目还有一些不太明显的技术要点:

第一,双向绑定和 受控组件

React 没有自动双向绑定的概念,只有受控组件,并且需要手动配置;由于功能是编辑完后点击后才渲染出来,所以 输入框的受控状态 不是渲染出来的那个状态(看源码容器组件有两个状态值),并且每编辑输入框一次,组件都重渲染;

第二,交互辅助状态

组件实现一项常见的用户友好体验的交互功能,就是在合适时候,更新按键才可用。由于逻辑较简单,此功能不需一个额外的 交互状态,它是 输入框状态的 派生状态(7第4和24行)。

交互流程,逻辑比较 复杂的时候,就会出现交互辅助状态,来提高用户交互体验。

项目结构分析

[keminlau@localhost 06_Enable]$ tree -I node_modules
.
├── package.json
├── src
│   ├── app.tsx // 顶层父组件(容器组件)
│   ├── hello.tsx // 交互状态输出的子组件(展示组件)
│   ├── index.html //
│   ├── index.tsx //
│   └── nameEdit.tsx // 交互状态输入的子组件(展示组件)
├── tsconfig.json
└── webpack.config.js

[keminlau@localhost 06_Enable]$ tree -I node_modules
.
├── package.json
├── src
│   ├── app.tsx // 顶层父组件(容器组件)
│   ├── hello.tsx // 交互状态输出的子组件(展示组件)
│   ├── index.html //
│   ├── index.tsx //
│   └── nameEdit.tsx // 交互状态输入的子组件(展示组件)
├── tsconfig.json
└── webpack.config.js

项目代码简要分析

app.tsx

import * as React from "react";
import { HelloComponent } from "./hello";
import { NameEditComponent } from "./nameEdit";

export const App = () => {
  const [name, setName] = React.useState("defaultUserName");
  const [editingName, setEditingName] = React.useState("defaultUserName");

  const loadUsername = () => {  };

  React.useEffect(() => {    loadUsername();  }, []);

  const setUsernameState = () => {
    setName(editingName);
  };

  return (
    <>
      <HelloComponent userName={name} />
      <NameEditComponent
        editingName={editingName}
        onNameUpdated={setUsernameState}
        onEditingNameUpdated={setEditingName}
        disabled={editingName === "" || editingName === name}
      />
    </>
  );
};

 

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *