7

image.png

Original link:
React those things
React hooks

The new environment has moved from Vue to the React stack, which is an interesting process.

In React, you will see many similarities with Vue, and there are also some differences. During the learning process, I encountered some doubts and recorded them.

  • How does useRef solve the null pointer problem?
  • What is the difference between useEffect and useCallback(useMemo)?
  • In addition to passing data through props, how can React pass data through context?
  • How is React.createElement in React.createElement(Input, props) understood?
  • What is FC in react? What does FC<[interface]> mean? What is the main use and the most abbreviated form?
  • What are the props, context, propTypes, contextTypes, defaultProps, displayName of the formal parameters of FC in React?
  • What does import { MouseEvent } from 'react' mean? What type is SyntheticEvent?
  • What does React.forwardRef mean? What does useImperativeHandle mean?

How does useRef solve the null pointer problem?

Typically, useRef is used to refer to a component's Dom node. A ref in Vue refers to a vue component. Unlike Vue, the ref in react not only refers to the Dom node, but also generates a memory-invariant object reference.

Example of null pointer caused by useState

const [foo, setFoo] = useState(null);

const handler = () => {
    setFoo("hello")
}

useEffect(() => {
    return () => {
      // 无论怎样foo都是null,给useEffect的deps加入foo也不行
      if (foo === "hello") {
          // do something...
      }
    }
}, [])

Proper example of using useRef (to solve the problem of object being null in event handler)

const foo = useRef(null)

const handler = () => {
    foo.current = "hello"
}

useEffect(() => {

    return () => {
      // foo.current为hello
      if (foo.current === "hello") {
          // do something...
      }
    }
}, [])

What is the reason for useRef to solve the null pointer problem?

  • During the component life cycle, the object pointed to by useRef always exists
  • useRef points to the same referenced object every time it renders

To sum up: The object generated by useRef has the same memory address during the component life cycle.

const refContainer = useRef(initialValue);

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

This works because useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.

To summarize the scenarios where useRef is used to solve the null pointer problem:

  • event handler
  • setTimeout,setInterval

What is the difference between useEffect and useCallback(useMemo)?

Browser execution stage: Visible modification (DOM manipulation, animation, transition) -> style rule calculation -> calculation of space and position -> draw pixel content -> multiple layer composition
The first four stages are all element-specific, and the last one is layer-specific. From point to point.
image

different execution times

useEffect executes the function after the rendering is complete, more precisely after the layout and paint are completed.

The function passed to useEffect will run after the render is committed to the screen.Unlike componentDidMount and componentDidUpdate, the function passed to useEffect fires after layout and paint

useCallback(useMemo) executes the function during rendering.

Remember that the function passed to useMemo runs during rendering.

Which are suitable for execution after rendering and which are suitable for execution during rendering

Execute after rendering is complete: Mutations (DOM manipulation), subscriptions (subscription), timers, logging
Executed during rendering: used for performance optimization that does not depend on the completion of rendering, and executes immediately as soon as the state changes

An example to illustrate the difference between useEffect and useMemo

The main problem solved by useMemo: How to control some functions not to be triggered when the DOM changes.
For example, in the following example, when the name is changed, useEffect will trigger the price function after the DOM rendering is completed, while useMemo can accurately trigger only the function that updates the name.

This is a very, very good example, more detailed blog post here: What is the difference between useMemo and useEffect? How to use useMemo

import React, {Fragment} from 'react'
import { useState, useEffect, useCallback, useMemo } from 'react'

const nameList = ['apple', 'peer', 'banana', 'lemon']
const Example = (props) => {
    const [price, setPrice] = useState(0)
    const [name, setName] = useState('apple')
    
    
    function getProductName() {
        console.log('getProductName触发')
        return name
    }
    // 只对name响应
    useEffect(() => {
        console.log('name effect 触发')
        getProductName()
    }, [name])
    
    // 只对price响应
    useEffect(() => {
        console.log('price effect 触发')
    }, [price])
  
    // memo化的getProductName函数   🧬🧬🧬
    const memo_getProductName = useMemo(() => {
        console.log('name memo 触发')
        return () => name  // 返回一个函数
    }, [name])

    return (
        <Fragment>
            <p>{name}</p>
            <p>{price}</p>
            <p>普通的name:{getProductName()}</p>
            <p>memo化的:{memo_getProductName ()}</p>
            <button onClick={() => setPrice(price+1)}>价钱+1</button>
            <button onClick={() => setName(nameList[Math.random() * nameList.length << 0])}>修改名字</button>
        </Fragment>
    )
}
export default Example

Click the price +1 button (through useMemo, the redundant memo_getProductName () is not triggered, only the price related function is triggered)

getProductName fires
price effect trigger

Click the Modify Name button (through useEffect, only the name is triggered)

name memo trigger
getProductName fires
name effect triggers
getProductName fires
Summarize

When useEffect faces some DOM rendering that depends on a certain state, there will be some performance problems, and useMemo can optimize this problem.
Finally, to sum up useMemo in one sentence, that is: useMemo can avoid some unnecessary repeated rendering and repeated execution problems that useEffect can't handle.

In addition to passing data through props, how can React pass data through context?

Assuming that the component level is deep, props need to be passed down level by level, which can be said to be a props hell problem.
Context-encapsulated components provide a way for components that need to receive data to pass across component levels and introduce superior props as .

Component definition context section

import * as React from 'react'
// myContext.ts
interface IContext {
     foo: string,
     bar?: number,
     baz: string
}
const myContext = React.createContext<IContext>({
     foo: "a",
     baz: "b"
})


interface IProps {
    data: IContext ,
}

const myProvider: React.FC<IProps> = (props) => {
     const {data, children} = props
     return <myContext.Provider value={data}>{children}</myContext.Provider>
}

export default myProvider;

export function useMyContext() {
  return useContext(myContext)
}

Using components and context sections

<!-- 组件包裹 -->
import myProvider from './myContext.ts'

<myProvider data={{foo: "foo", baz: "baz"}}>
    <div className="root">
        <div className="parent">
            <Component1 />
            <Component2 />
        </div>
     </div>
</myProvider>
// Component1
import  {useMyContext} from './myContext.ts'
const {foo, baz} = useMyContext()

const Compoonent1 = () => {
    return (<div>{foo}{baz}</div>)
}
export Component1

How is React.createElement in React.createElement(Input, props) understood?

React.createElement()

React.createElement(
    type,
    [props],
    [...children]
)

Returns a new React element of the specified type.

Type This parameter can be:

  • a "tagname string" (eg "div", "span")
  • A React component type (a class or a function)
  • A React fragment type

Components written in JSX will eventually be parsed as React.createElement(). If you use the JSX way, you don't need to call React.createElement() explicitly.

React.createElement(Input, props)

Based on antd, encapsulates common form component methods.

// generator.js
import React from "react";
import { Input, Select } from "antd";

const components = {
  input: Input,
  select: Select
};

export default function generateComponent(type, props) {
  return React.createElement(components[type], props);
}

Simply use this generic form component method:

import generateComponent from './generator'

const inputComponent = generateComponent('input', props)
const selectComponent = generateComponent('select', props)

You might think the above method is a bit useless, but if you generate components in batches, this method is very useful.

// components.js
import React from "react";
import generateComponent from "./generator";

const componentsInfos = [
  {
    type: "input",
    disabled: true,
    defaultValue: "foo"
  },
  {
    type: "select",
    autoClear: true,
    dropdownStyle: { color: "red" }
  }
];

export default class Components extends React.Component {
  render() {
    return componentsInfos.map((item) => {
      const { type, ...props } = item;
      return <>{generateComponent(type, props)}</>;
    });
  }
}

A specific example can be viewed: https://codesandbox.io/s/react-component-generator-onovg?file=/src/index.js

Based on this method, reusable business components can be encapsulated: form business components, table business components, etc., which will greatly liberate productivity!

What is FC in react? What does FC<[interface]> mean? What is the main use and the most abbreviated form?

What is FC in react?

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

FC is the abbreviation of FunctionComponent, and FunctionComponent is a generic interface.

What does FC<[interface]> mean?

It is to provide a functional component environment for wrapping components.
why? Because hooks can be used inside functional components.

functional component

const Component = (props) => {
    // 这里可以使用hooks
    return <div />
}
或者
function Component(props) {
  // 这里可以使用hooks
  return <div />;
}

What is the main use and the most abbreviated form?

Public functional components in the project, used as component containers to provide hooks context.

// Container.js
import React, { FC } from 'react'

interface IProps {
     children: any
}

const Container: FC<IProps> = (props) =>  {
  return (
    <div>
      {props.children}
    </div>
  )
}

export default Container
// 使用
<Container>
    <Component1 />
    <Component2 />
</Container>

What are the props, context, propTypes, contextTypes, defaultProps, displayName of the formal parameters of FC in React?

type FC<P = {}> = FunctionComponent<P>;

interface FunctionComponent<P = {}> {
        (props: PropsWithChildren<P>, context?: any): ReactElement | null;
        propTypes?: WeakValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
}

type PropsWithChildren<P> = P & { children?: ReactNode };

Among them, props and context are formal parameters of function components.
And propTypes, contextTypes, defaultProps, displayName are all properties of the component's function component.

const Foo: FC<{}> = (props, context) => {
    return (
        <div>{props.children}</div>
    )
}
Foo.propTypes = ...
Foo.contextTypes = ...
Foo.defaultProps = ...
Foo.displayName = ...

What is the difference between react functional components and pure functional components?

1.React functional components must return ReactElement or null, the return value of pure functional components is not limited
2. The props of react functional components limit the type of children to ReactNode, and pure functional components are not limited
3.React functional components have type constraints such as propTypes, contextTypes, defaultProps, displayName, etc. Pure functional components are not limited

https://stackoverflow.com/questions/53935996/whats-the-difference-between-a-react-functioncomponent-and-a-plain-js-function

What does import { MouseEvent } from 'react' mean? What type is SyntheticEvent?

What does import { MouseEvent } from 'react' mean?

Good article: https://fettblog.eu/typescript-react/events/#1

  • for event type constraints
  • Besides MouseEvent, there are AnimationEvent, ChangeEvent, ClipboardEvent, CompositionEvent, DragEvent, FocusEvent, FormEvent, KeyboardEvent, MouseEvent, PointerEvent, TouchEvent, TransitionEvent, WheelEvent. As well as SyntheticEvent
  • You can use the MouseEvent<HTMLButtonElement> constraint to fire only the HTML button DOM's events
  • InputEvent is special because it is an experimental event, so it can be replaced by SyntheticEvent

What type is SyntheticEvent?

Synthetic -> synthetic

In React, almost all events inherit the SyntheticEvent interface.
SyntheticEvent is a cross-browser browser event wrapper, usually used to replace event types like InpuEvent.

interface SyntheticEvent<T = Element, E = Event> extends BaseSyntheticEvent<E, EventTarget & T, EventTarget> {}
interface BaseSyntheticEvent<E = object, C = any, T = any> {
    nativeEvent: E;
    currentTarget: C;
    target: T;
    bubbles: boolean;
    cancelable: boolean;
    defaultPrevented: boolean;
    eventPhase: number;
    isTrusted: boolean;
    preventDefault(): void;
    isDefaultPrevented(): boolean;
    stopPropagation(): void;
    isPropagationStopped(): boolean;
    persist(): void;
    timeStamp: number;
    type: string;
}

What does React.forwardRef mean? What does useImperativeHandle mean?

In short, refs forwarding is to get the DOM node inside the component.
React.forwardRef means that Refs forward , which is mainly used to automatically pass ref to a sub-component through a component, which is common in reusable component libraries.

When using forwardRef, you can let some components receive ref and pass it down to subcomponents, which can also be said to "forward" to subcomponents.

There are no components forwarded using refs.

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.children}
    </button>
  );
}

Components forwarded using refs.

const FancyButton = React.forwardRef((props, ref)=>{
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
})

how to use?

// 创建一个ref变量
const ref = React.createRef();
// 将ref变量传入FancyButton,FancyButton将ref变量转发给button
<FancyButton ref={ref}></FancyButton>
// ref.current指向button DOM节点

There are also different refs mechanisms in vue, but if vue wants to obtain the DOM nodes inside the sub-component, it needs to be obtained level by level, such as this.$refs.parent.$refs.child , which will lead to serious component-level dependencies.
Compared with Vue, React's refs forwarding component level is lighter, and the code is more readable and maintainable.

What does useImperativeHandle mean?

import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    publicFocus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />
});

const App = props => {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button
        onClick={() => fancyInputRef.current.publicFocus()}
      >父组件调用子组件的 focus</button>
    </div>
  )
}

ReactDOM.render(<App />, root);

The above example is different from direct forwarding ref. Directly forwarding ref directly applies the ref parameter on the function in React.forwardRef to the ref attribute of the returned element. In fact, the parent and child components refer to the current object of the same ref. Officially, it is not recommended to use such ref passthrough, but after using useImperativeHandle, parent and child components can have their own refs, pass the parent component's ref through React.forwardRef, and use the useImperativeHandle method to customize the ref open to the parent component. current.

Looking forward to communicating with you and making progress together:

  • WeChat public account: Dada big front end / excellent_developers
  • Front-end Q&A mutual aid planet: t.zsxq.com/yBA2Biq
Strive to be an excellent front-end engineer!

趁你还年轻
4.1k 声望4.1k 粉丝