Skip to content

React 设计规范

高内聚

High Cohesion

单一职责

SRP ( Single Responsibility Principle )

  • 组件内部应当逻辑紧密
  • 每个组件只负责各自的功能,不要杂糅多个功能逻辑
  • 复杂的界面与交互建议尽可能细分拆为多个独立的小组件
tsx
const Buttons: React.FC = () => {
  const [count, setCount] = useState<number>(0);
  const increment = () => setCount((s) => s + 1);
  const decrease = () => setCount((s) => s - 1);
  return (
    <>
      <div>{count}</div>
      <button onClick={increment}>+1</button>
      <button onClick={decrease}>-1</button>
    </>
  );
};
tsx
const Buttons: React.FC = () => {
  const { count, increment, decrease } = useButton();
  return (
    <>
      <div>{count}</div>
      <IncreaseButton onClick={increment}>+1</IncreaseButton>
      <DecreaseButton onClick={decrease}>-1</DecreaseButton>
    </>
  );
};

type Props = React.PropsWithChildren<{ onClick: VoidFunction }>;

const IncreaseButton: React.FC<Props> = ({ children, onClick }) => {
  return <button onClick={onClick}>{children}</button>;
};

const DecreaseButton: React.FC<Props> = ({ children, onClick }) => {
  return <button onClick={onClick}>{children}</button>;
};

const useButton = () => {
  const [count, setCount] = useState<number>(0);
  const increment = () => setCount((s) => s + 1);
  const decrease = () => setCount((s) => s - 1);
  return { count, increment, decrease };
};

低耦合

Low Coupling

避免直接访问状态

  • 父组件通过 context、props 将数据和回调函数传递给子组件
  • 子组件只负责渲染和触发回调,而不直接操作父组件的状态或逻辑
tsx
import React from "react";

type ChildRef = {
  setText: (text: string) => void;
};

const Parent: React.FC = () => {
  const childRef = React.useRef<ChildRef>(null);
  const handleClick = () => {
    if (childRef.current) childRef.current.setText("新值");
  };
  return (
    <>
      <Child ref={childRef} />
      <button onClick={handleClick}>更新</button>
    </>
  );
};

const Child = React.forwardRef<ChildRef, {}>((_, ref) => {
  const [text, setText] = React.useState<string>("初始值");
  React.useImperativeHandle(ref, () => ({
    setText,
  }));
  return <div>{text}</div>;
});
tsx
import React from "react";

const Parent: React.FC = () => {
  const [text, setText] = React.useState<string>("初始值");
  return <Child text={text} setText={setText} />;
};

type ChildProps = {
  text: string;
  setText: (newVal: string) => void;
};

const Child: React.FC<ChildProps> = ({ text, setText }: ChildProps) => {
  return (
    <>
      <div>{text}</div>
      <button onClick={() => setText("新值")}>更新</button>
    </>
  );
};

降低跨层级耦合

Context API Pattern、Redux Pattern...

  • 使用全局状态 Context、Store 管理深处组件的间的共享的数据
  • 不建议通过 props 层层传递
tsx
type Props = { message: string };

const App: React.FC = () => <Level1 message="xxx" />;
const Level1: React.FC<Props> = ({ message }) => <Level2 message={message} />;
const Level2: React.FC<Props> = ({ message }) => <Level3 message={message} />;
const Level3: React.FC<Props> = ({ message }) => <div>{message}</div>;
tsx
import React from "react";

type MessageContextType = {
  message: string;
};

const MessageContext = React.createContext<MessageContextType>({
  message: "",
});

const App: React.FC = () => {
  return (
    <MessageContext.Provider value={{ message: "值" }}>
      <Level1 />
    </MessageContext.Provider>
  );
};
const Level1: React.FC = () => <Level2 />;
const Level2: React.FC = () => <Level3 />;
const Level3: React.FC = () => {
  const context = React.useContext(MessageContext);
  if (!context) return null;
  return <div>{context.message}</div>;
};

分离界面与功能

Hooks Pattern

  • 组件是无状态的只负责渲染与交互
  • 功能逻辑抽离到自定义 Hooks
tsx
const Button: React.FC = () => {
  const [count, setCount] = React.useState<number>(0);
  const handleClick = () => setCount(count + 1);
  return (
    <button
      onClick={handleClick}
      style={{
        padding: "10px",
        backgroundColor: "pink",
        border: "2px solid blue",
      }}
    >
      {count}
    </button>
  );
};
tsx
const Button: React.FC = () => {
  const { count, handleClick } = useButton();
  return (
    <button
      onClick={handleClick}
      style={{
        padding: "10px",
        backgroundColor: "pink",
        border: "2px solid blue",
      }}
    >
      {count}
    </button>
  );
};

const useButton = () => {
  const [count, setCount] = React.useState<number>(0);
  const handleClick = () => setCount(count + 1);
  return { count, handleClick };
};

分离容器与展示界面

Container-Component Pattern ( Smart-Dumb Component Pattern )

  • 容器组件:负责数据获取、状态管理、功能逻辑
  • 展示组件:负责界面渲染,无状态的,通过 props 接收容器传递的数据和回调函数
tsx
type User = {
  id: number;
  name: string;
  email: string;
};

const UserList: React.FC = () => {
  const [users, setUsers] = React.useState<User[]>([]);
  React.useEffect(() => {
    fetch("URL")
      .then((res) => res.json())
      .then((res) => setUsers(res));
  }, []);
  return (
    <>
      {users.map((user) => (
        <div key={user.id}>
          {user.name} - {user.email}
        </div>
      ))}
    </>
  );
};
tsx
type User = {
  id: number;
  name: string;
  email: string;
};

type UserListProps = {
  users: User[];
};

const UserListContainer: React.FC = () => {
  const [users, setUsers] = React.useState<User[]>([]);
  React.useEffect(() => {
    fetch("URL")
      .then((res) => res.json())
      .then((res) => setUsers(res));
  }, []);
  return <UserList users={users} />;
};

const UserList: React.FC<UserListProps> = ({ users }) => {
  return (
    <>
      {users.map((user) => (
        <div key={user.id}>
          {user.name} - {user.email}
        </div>
      ))}
    </>
  );
};