React

头像
Lebi
    阅读 7 分钟

    cloud setups

    组件的写法

    function

    function Hello({ ame }: Props) {
        return (
            <div>Hello, {name}</div>
        );
    }
    
    export default Hello;
    type ButtonProps = {
        text: string
    }
    const Button: React.FC<ButtonProps> = ({ text }) => {
        return <button>{text}</button>
    }
    export default Button

    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
    适用情况:

    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>
        </>
      );
    }

    5. useContext

    const value = useContext(MyContext);

    接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>value prop 决定。

    6. 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>
      ];
    }

    上下文(Context)

    上下文(Context) 提供了一种通过组件树传递数据的方法,无需在每个级别手动传递 props 属性。
    使用 Context 可能比替代方案更简单的常见示例包括管理当前本地设置,主题或数据缓存。

    在使用 Context 之前

    当一些数据需要在不同的嵌套级别上被_许多_组件访问时,首先考虑使用 Context 。 请谨慎使用它,因为它使组件重用更加困难。

    API

    • 通过 createContext 创建一个名为 color 的 context
    • 通过 Provider 的 value 属性传值
    • 通过 Consumer 的 props 接收值

    React.Children.only

    验证 children 是否只有一个子节点(一个 React 元素),如果有则返回它,否则此方法会抛出错误。

    React.Children.only(children)

    ReactNode

    ReactNode 是虚拟 DOM 的基本构建,可以是以下任意一种核心类型

    • ReactElement

      它是 React 中的基础类型,是 DOM 中 Element 的一种轻量、无状态、不可变的虚拟表现形式

    • ReactText

      它是一个数字或者字符串,它代表了文本内容,是 DOM 中的文本节点的虚拟表示形式

    ReactElement 和 ReactText 都是 ReactNode 。 一个 ReactNode 的数组称为 ReactFragment 。


    定义事件处理程序

    const App = () => {
        const handleClick: React.MouseEventHandler<HTMLButtonElement> = e => {
            console.log(e)
        }
        return <button onClick={handleClick}>Click</button>
    }
    1. Event Handler
      我们必须先选择这是要处理一下Event的Handler,Event种类有很多,都是以Event结尾,像是MouseEvent,FormEvent,KeyboardEvent等等,可参考React官方文件
    2. Target Element
      接下来我们必须定义Handler的作用目标是什么,以示例来说,我们要处理的是作用在“按钮”上面的点击事件,所以我们必需要使用HTMLButtonElement来宣告我们的作用目标,作用目标有很多种,都是HTML开头,Element结尾,像是HTMLFormElement,HTMLDivElement等等,可参考MDN


    React.forwardRef

    父组件操作子组件DOM,接收一个函数组件,这个函数组件可以接收ref参数
    React.forwardRef<T, P = {}>只需要传props的类型和ref的类型,第一个Tref的类型,Pprops的类型

    React.ForwardRefRenderFunction

    定义为该类型的函数可以放进React.forwardRef函数中作为参数

    const InternalButton: React.ForwardRefRenderFunction<unknown, ButtonProps> = (props, ref) => {
      const buttonNode = (
        <button
          {...(rest as NativeButtonProps)}
          type={htmlType}
          className={classes}
          onClick={handleClick}
          ref={buttonRef}
        >
          {iconNode}
          {kids}
        </button>
      );
      if (isUnborderedButtonType(type)) {
        return buttonNode;
      }
    
      return <Wave>{buttonNode}</Wave>;
    };
    
    const Button = React.forwardRef<unknown, ButtonProps>(InternalButton) as CompoundedComponent;

    Partial

    将类型定义的所有属性都修改为可选。

    type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
    
    // 等价于
    type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>;
    
    type ButtonProps = {
      AnchorButtonProps?: typeof AnchorButtonProps;
      NativeButtonProps?: typeof NativeButtonProps;
    }

    Enum 类型

    尽量避免使用枚举类型,可以用以下代替:

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

    React+TypeScript Cheatsheets
    你真的了解React Hooks吗?
    React笔记


    Lebi
    1 声望2 粉丝