zoukankan      html  css  js  c++  java
  • React 类组件的一些基本概念

    谈谈 React 里面的一些类型及使用场景

    • React.Component<P,S,SS>, 这个类型绝对是 react 里面的一哥,P 是 props, S: State, SS: SnapShot. 凡是 class 组件,都得继承这个基类。下面是这个类的 type.d.ts. 生命周期主要参考下面这副图 类生命周期 .
      这幅图是新旧生命周期执行的图,橘色是 deprecated, 绿色是新的,新老不能同时定义,否则会报错。
    interface Component<P = {}, S = {}, SS = any>
      extends ComponentLifecycle<P, S, SS> {}
    

    ComponentLifecycle

    interface ComponentLifecycle<P, S, SS = any>
      extends NewLifecycle<P, S, SS>,
        DeprecatedLifecycle<P, S> {
      /**
       * Called immediately after a component is mounted. Setting state here will trigger re-rendering.
       */
      componentDidMount?(): void;
      /**
       * Called to determine whether the change in props and state should trigger a re-render.
       *
       * `Component` always returns true.
       * `PureComponent` implements a shallow comparison on props and state and returns true if any
       * props or states have changed.
       *
       * If false is returned, `Component#render`, `componentWillUpdate`
       * and `componentDidUpdate` will not be called.
       */
      shouldComponentUpdate?(
        nextProps: Readonly<P>,
        nextState: Readonly<S>,
        nextContext: any
      ): boolean;
      /**
       * Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as
       * cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`.
       */
      componentWillUnmount?(): void;
      /**
       * Catches exceptions generated in descendant components. Unhandled exceptions will cause
       * the entire component tree to unmount.
       */
      componentDidCatch?(error: Error, errorInfo: ErrorInfo): void;
    }
    

    NewLifecycle

    interface NewLifecycle<P, S, SS> {
      /**
       * Runs before React applies the result of `render` to the document, and
       * returns an object to be given to componentDidUpdate. Useful for saving
       * things such as scroll position before `render` causes changes to it.
       *
       * Note: the presence of getSnapshotBeforeUpdate prevents any of the deprecated
       * lifecycle events from running.
       */
      getSnapshotBeforeUpdate?(
        prevProps: Readonly<P>,
        prevState: Readonly<S>
      ): SS | null;
      /**
       * Called immediately after updating occurs. Not called for the initial render.
       *
       * The snapshot is only present if getSnapshotBeforeUpdate is present and returns non-null.
       */
      componentDidUpdate?(
        prevProps: Readonly<P>,
        prevState: Readonly<S>,
        snapshot?: SS
      ): void;
    }
    

    DeprecatedLifecycle

    interface DeprecatedLifecycle<P, S> {
      /**
       * Called immediately before mounting occurs, and before `Component#render`.
       * Avoid introducing any side-effects or subscriptions in this method.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use componentDidMount or the constructor instead; will stop working in React 17
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      componentWillMount?(): void;
      /**
       * Called immediately before mounting occurs, and before `Component#render`.
       * Avoid introducing any side-effects or subscriptions in this method.
       *
       * This method will not stop working in React 17.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use componentDidMount or the constructor instead
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      UNSAFE_componentWillMount?(): void;
      /**
       * Called when the component may be receiving new props.
       * React may call this even if props have not changed, so be sure to compare new and existing
       * props if you only want to handle changes.
       *
       * Calling `Component#setState` generally does not trigger this method.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use static getDerivedStateFromProps instead; will stop working in React 17
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
      /**
       * Called when the component may be receiving new props.
       * React may call this even if props have not changed, so be sure to compare new and existing
       * props if you only want to handle changes.
       *
       * Calling `Component#setState` generally does not trigger this method.
       *
       * This method will not stop working in React 17.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use static getDerivedStateFromProps instead
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      UNSAFE_componentWillReceiveProps?(
        nextProps: Readonly<P>,
        nextContext: any
      ): void;
      /**
       * Called immediately before rendering when new props or state is received. Not called for the initial render.
       *
       * Note: You cannot call `Component#setState` here.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use getSnapshotBeforeUpdate instead; will stop working in React 17
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      componentWillUpdate?(
        nextProps: Readonly<P>,
        nextState: Readonly<S>,
        nextContext: any
      ): void;
      /**
       * Called immediately before rendering when new props or state is received. Not called for the initial render.
       *
       * Note: You cannot call `Component#setState` here.
       *
       * This method will not stop working in React 17.
       *
       * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps
       * prevents this from being invoked.
       *
       * @deprecated 16.3, use getSnapshotBeforeUpdate instead
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update
       * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path
       */
      UNSAFE_componentWillUpdate?(
        nextProps: Readonly<P>,
        nextState: Readonly<S>,
        nextContext: any
      ): void;
    }
    

    • React.FC

      函数组件,这个是绝对的后起之秀,react 的希望,官方推荐使用定义组件的方案。 它的相关类型比较多。例如 无状态组件,函数组件等等,它的运行过程就相对简单多了,就是函数的执行,从上往下执行,注意几个底层的 hook 函数

      • const [val,setVal]=React.useState<S>(initialState), 它的特点是函数第一次运行的时候,或者val !==undefine 的时候才会执行,第二次以后就不会执行了,其实是内部直接返回了. 注意,它必须至于 function 内部的最顶层,不能存在于任何块作用域。否则会报错。
      • const context = React.useContext(Context), 跟上面的类似,也是第一次执行,以后只有 Context.provider 的值变化的时候才会执行。
      • const ref = React.useRef<r>(), 这个个人绝对可以看作是上面两个的基础,它的作用是确保 ref, 在函数内部永远唯一,不管函数执行多少次。
        一句话,hook 函数的目的只有一个,就是确保函数在 React setState 多次时,有些变量能够被共享,相当于提供了一个上下文。
        我们来看一下FC的类型定义。
    /**
     * @deprecated as of recent React versions, function components can no
     * longer be considered 'stateless'. Please use `FunctionComponent` instead.
     *
     * @see [React Hooks](https://reactjs.org/docs/hooks-intro.html)
     */
    type StatelessComponent<P = {}> = FunctionComponent<P>;
    
    type FC<P = {}> = FunctionComponent<P>;
    
    interface FunctionComponent<P = {}> {
      (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
      propTypes?: WeakValidationMap<P>;
      contextTypes?: ValidationMap<any>;
      defaultProps?: Partial<P>;
      displayName?: string;
    }
    

    • React.ForwardRefRenderFunction<TRef,P> 以及著名的 React.forwardRef<TRef,P>() 它是用来定义组件,同时将 ref 传递给内部的组件,因为一般情况下,ref 会被赋予当前组件的值,而这个方法的作用就是洞穿当前组件,将 ref 往下传递。 我们来看一下类型定义,很清楚.forwardRef() 返回的其实是一个方法,同时含有一下属性.
    interface ForwardRefRenderFunction<T, P = {}> {
      (props: PropsWithChildren<P>, ref: ForwardedRef<T>): ReactElement | null;
      displayName?: string;
      // explicit rejected with `never` required due to
      // https://github.com/microsoft/TypeScript/issues/36826
      /**
       * defaultProps are not supported on render functions
       */
      defaultProps?: never;
      /**
       * propTypes are not supported on render functions
       */
      propTypes?: never;
    }
    
    function forwardRef<T, P = {}>(
      render: ForwardRefRenderFunction<T, P>
    ): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;
    
    // will show `ForwardRef(${Component.displayName || Component.name})` in devtools by default,
    // but can be given its own specific name
    interface ForwardRefExoticComponent<P> extends NamedExoticComponent<P> {
      defaultProps?: Partial<P>;
      propTypes?: WeakValidationMap<P>;
    }
    interface NamedExoticComponent<P = {}> extends ExoticComponent<P> {
      displayName?: string;
    }
    
    // TODO: similar to how Fragment is actually a symbol, the values returned from createContext,
    // forwardRef and memo are actually objects that are treated specially by the renderer; see:
    // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/ReactContext.js#L35-L48
    // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/forwardRef.js#L42-L45
    // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/memo.js#L27-L31
    // However, we have no way of telling the JSX parser that it's a JSX element type or its props other than
    // by pretending to be a normal component.
    //
    // We don't just use ComponentType or SFC types because you are not supposed to attach statics to this
    // object, but rather to the original function.
    interface ExoticComponent<P = {}> {
      /**
       * **NOTE**: Exotic components are not callable.
       */
      (props: P): ReactElement | null;
      readonly $$typeof: symbol;
    }
    

    • memo() vs React.useMemo() vs React.PureComponent React.memo() 它是一个 HOC,只有当内部组件的输入参数变化了,或者内部组件使用了 useState,useReducer,useContext 这些 hook 函数,它才会触发 render. 否则就直接返回上次 render 的内部组件.
      简单的说,memo()函数执行后返回的是内部组件,跟内部组件几乎一模一样,只是,它的更新规则变了。同时它的比较还是浅比较。它属于 HOC。
      useMemo() 它是 hook 函数,它将返回的值进行缓存,除非以来项发生变化,否则值不变。它本身是一个函数。
      这里还要提到 useCallback(), 跟 useMemo() 的唯一差别是它缓存的是函数。通常用于事件响应函数的缓存等。
      PureComponent, 它跟普通的 Component 的差别是默认实现了 componentshouldupdate() 方法,跟 memo() 类似。
    function memo<T extends ComponentType<any>>(
      Component: T,
      propsAreEqual?: (
        prevProps: Readonly<ComponentProps<T>>,
        nextProps: Readonly<ComponentProps<T>>
      ) => boolean
    ): MemoExoticComponent<T>;
    
    // will show `Memo(${Component.displayName || Component.name})` in devtools by default,
    // but can be given its own specific name
    type MemoExoticComponent<T extends ComponentType<any>> = NamedExoticComponent<
      ComponentPropsWithRef<T>
    > & {
      readonly type: T;
    };
    
    // I made 'inputs' required here and in useMemo as there's no point to memoizing without the memoization key
    // useCallback(X) is identical to just using X, useMemo(() => Y) is identical to just using Y.
    /**
     * `useCallback` will return a memoized version of the callback that only changes if one of the `inputs`
     * has changed.
     *
     * @version 16.8.0
     * @see https://reactjs.org/docs/hooks-reference.html#usecallback
     */
    // TODO (TypeScript 3.0): <T extends (...args: never[]) => unknown>
    function useCallback<T extends (...args: any[]) => any>(
      callback: T,
      deps: DependencyList
    ): T;
    /**
     * `useMemo` will only recompute the memoized value when one of the `deps` has changed.
     *
     * Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in
     * the second argument.
     *
     * ```ts
     * function expensive () { ... }
     *
     * function Component () {
     *   const expensiveResult = useMemo(expensive, [expensive])
     *   return ...
     * }
     * ```
     *
     * @version 16.8.0
     * @see https://reactjs.org/docs/hooks-reference.html#usememo
     */
    // allow undefined, but don't make it optional as that is very likely a mistake
    function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;
    
    class PureComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {}
    

    • React.cloneElement() 一般,我们如果希望改变一个组件变量的输入参数或者 ref,我们就会调用它。因为我们不知道它内容是什么,所以需要这个方法,特别是写一个同样组件时,希望给传进来的组件添加一些额外功能的时候,类似与 Angular 里面的 TemplateRef<any>.
    • ReactDom.render(), 这个方法是将一个 React 组件插入到 React Virtual Dom 树上,类似与 Angular 里面的 AppRef.AttachRef()。这个很厉害的,可以通过编程的方式动态添加组件。
  • 相关阅读:
    Clean Code(三):注释
    Clean Code(二):函数
    mysql中查询某字段所在的表方法
    对于POI的XSSFCell 类型问题
    Clean Code 笔记 (一):命名
    java 注解
    搭建Eureka服务时报Cannot execute request on any known server 错误
    Jquery获取子父类方法
    Oracle 查询id相同多个数据取一条
    Ajax的使用及后台如何传参
  • 原文地址:https://www.cnblogs.com/kongshu-612/p/14920671.html
Copyright © 2011-2022 走看看