关于typescript:React

cloud setups

  • TypeScript Playground with React just if you are debugging types (and reporting issues), not for running code
  • CodeSandbox – cloud IDE, boots up super fast
  • Stackblitz – cloud IDE, boots up super fast

组件的写法

function

function Hello({ ame }: Props) {
    return (
        <div>Hello, {name}</div>
    );
}

export default Hello;

class

class Hello extends React.Component<Props, object> {
    render() {
        const { name } = this.props;
        return (
            <div>Hello, {name}</div>
        );
    }
}

函数式组件和类组件的不同

React Hooks因为是函数式组件,在异步操作或者应用useCallBack、useEffect、useMemo等API时会造成闭包。

Hooks

1. useState

function Counter({initialCount}) {
  const [count, setCount] = useState<nubmer>(initialCount);
  return (
    <> Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> </>
  );
}

2. useReducer

reducer: (state, action) => newState
实用状况:

  • state 逻辑较简单且蕴含多个子值
  • 下一个 state 依赖于之前的 state
  • 会触发深更新的组件做性能优化,因为你能够向子组件传递 dispatch 而不是回调函数 。
const initialState = { count: 0 };

type ACTIONTYPE =
  | { type: "increment"; payload: number }
  | { type: "decrement"; payload: string };

function reducer(state: typeof initialState, action: ACTIONTYPE) {
  switch (action.type) {
    case "increment":
      return { count: state.count + action.payload };
    case "decrement":
      return { count: state.count - Number(action.payload) };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "decrement", payload: "5" })}>
        -
      </button>
      <button onClick={() => dispatch({ type: "increment", payload: 5 })}>
        +
      </button>
    </>
  );
}
惰性初始化

init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg)

import * as React from "react";
import { useReducer } from "react";

const initialCount = 0;

type ACTIONTYPE =
  | { type: "increment"; payload: number }
  | { type: "decrement"; payload: string }
  | { type: "reset"; payload: number };

function init(initialCount: number) {
  return { count: initialCount };
}

function reducer(state: {count: number}, action: ACTIONTYPE) {
  switch (action.type) {
    case "reset":
      return init(action.payload);
    case "increment":
      return { count: state.count + action.payload };
    case "decrement":
      return { count: state.count - Number(action.payload) };
    default:
      throw new Error();
  }
}

export function Counter() {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({ type: "reset", payload: initialCount })}
      >
        reset
      </button>
      <button onClick={() => dispatch({ type: "decrement", payload: "5" })}>
        -
      </button>
      <button onClick={() => dispatch({ type: "increment", payload: 5 })}>
        +
      </button>
    </>
  );
}

3. useEffect

function DelayedEffect(props: { timerMs: number }) {
  const { timerMs } = props;

  useEffect(() => {
    setTimeout(() => {
      /* do stuff */
    }, timerMs);
  }, [timerMs]);
  // better; use the void keyword to make sure you return undefined
  return null;
}

4. useRef

const ref1 = useRef<HTMLElement>(null!);
const ref2 = useRef<HTMLElement>(null);
const ref3 = useRef<HTMLElement | null>(null);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内放弃不变。

function TextInputWithFocusButton() {
  // initialise with null, but tell TypeScript we are looking for an HTMLInputElement
  const inputEl = React.useRef<HTMLInputElement>(null);
  const onButtonClick = () => {
    // strict null checks need us to check if inputEl and current exist.
    // but once current exists, it is of type HTMLInputElement, thus it
    // has the method focus! ✅
    if (inputEl && inputEl.current) {
      inputEl.current.focus();
    }
  };
  return (
    <>
      {/* in addition, inputEl only can be used with input elements. Yay! */}
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Custom Hooks

export function useLoading() {
  const [isLoading, setState] = React.useState(false);
  const load = (aPromise: Promise<any>) => {
    setState(true);
    return aPromise.finally(() => setState(false));
  };
  return [isLoading, load] as const; // infers [boolean, typeof load] instead of (boolean | typeof load)[]
}

也能够写成:

export function useLoading() {
  const [isLoading, setState] = React.useState(false);
  const load = (aPromise: Promise<any>) => {
    setState(true);
    return aPromise.finally(() => setState(false));
  };
  return [isLoading, load] as [
    boolean,
    (aPromise: Promise<any>) => Promise<any>
  ];
}

Enum 类型
尽量避免应用枚举类型,能够用以下代替:

export declare type Position = "left" | "right" | "top" | "bottom";

React+TypeScript Cheatsheets
你真的理解React Hooks吗?

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理