The hooks in the React

Learning about this requires some pre-knowledge, typescript type definitions and React hooks. It is recommended to look at _ when looking at type declarations for hooks.

  1. useState
  2. useMemo
  3. useCallback
  4. useRef
  5. useReducer
  6. useContext

useState

UseState provides function components that can also be dynamically modified, equivalent to the state of the class component; The useState type is passed in by the stereotype: the state type is defined and given an initial value

interface IProps { name: string; } // React.FunctionComponent -> React.FC support const State: React.FunctionComponent<IProps> = (props: IProps) => { let [count, setCount] = useState<number>(0); return (<> <div> <h1>{count}</h1> <h2>{props.name}</h2> </div> </>) }Copy the code

If there is no initial value can use joint property sets the initial value is null, such as < number | null >, but need to pay attention to here, subsequent to an empty value when using state judgment, usually use optional chain to visit a? .b -> a && a.b

interface IObject { num: number; }... let [count, setCount] = useState<IObject | null>(null); . <h1>{count? .num}</h1>Copy the code

useMemo

UseMemo is an optimization for rendering components, and the passing pattern specifies the return value (though it is generally not defined in use)

const memoized = useMemo<string>(() => {
  return name;
}, [name])
Copy the code

useCallback

useRef

UseRef is equivalent to creating a ref and serves two purposes:

  1. It can be used to save the latest value of a state, or to obtain the latest value of state when processing state asynchronously.
  2. Associated with the tag, DOM elements can be obtained via.current.

Save state to a MutableRefObject type

const Ref: React.FC = () => { let [count, setCount] = useState<number>(0); let divRef = useRef<number>(0); return ( <div> <h1>{count}</h1> <button onClick={() => { setCount(count + 10); divRef.current = count + 10; }}>+10</button> <button onClick={() => {setTimeout(() => {// This must get the latest value setCount(divref.current-10); divRef.current -= 10; }, 1000) }}>-10</button> </div> ) }Copy the code

DOM association, for the type of ref is not known when the type of TS can be used to judge, and then determine.

const Ref: React.FC = () => { let divRef = useRef<HTMLHeadingElement>(null); return ( <div> <h1 ref={divRef}>ref</h1> <button onClick={(event: React.MouseEvent)=>{ console.log('button', event.target); console.log('h1', divRef.current); DOM</button> </div>Copy the code

useReducer

When the state is complex and multiple Usestates are used, the useReducer can be used for centralized control.

enum ActionType { INCREMENT_COUNT = 'INCREMENT_COUNT', DECREMENT_COUNT = 'DECREMENT_COUNT' } interface IState { count: number; } interface IAction { type: ActionType, value: number; } const initializeState = { count: 0 } const reducer: React.Reducer<IState, IAction> = (state: IState, action: IAction) => { switch (action.type) { case 'INCREMENT_COUNT': return { ... state, count: state.count + action.value } case 'DECREMENT_COUNT': return { ... state, count: state.count - action.value } default: return { ... state } } } const Reducer: React.FC = () => { let [state, dispatch] = useReducer<React.Reducer<IState, IAction>>(reducer, initializeState); return ( <div className="reducer"> <h1>{state.count}</h1> <button onClick={() => { dispatch({ type: ActionType.INCREMENT_COUNT, value: 10 }) }}>+10</button> <button onClick={() => { dispatch({ type: ActionType.DECREMENT_COUNT, value: 5 }) }}>-5</button> </div> ) }Copy the code

useContext

UseContext allows you to pass data in context

interface IArticle { id: number; title: string; } interface IContext { articles: IArticle[]; style? : React.CSSProperties; } type IProps = { name: string; // children: react.reactNode []; // Children: react.reactNode []; // Children: react.functionComponent []; // children: React.ReactChild[]; // children: JSX.Element[]; } const initlizeArticles = [ { id: 1, title: 'first' }, { id: 2, title: 'second' } ] const ArticleContext = createContext<IContext>({} as IContext); const ArticleProvider: FC<IProps> = ({ children, style }) => { let [articles] = useState<IArticle[]>(initlizeArticles); let context = { articles, style }; return ( <ArticleContext.Provider value={context}> {children} </ArticleContext.Provider> ) } const ShowArticles: FC = () => { let { articles = [], style } = useContext<IContext>(ArticleContext); return ( <div style={style}> { articles.map((article: IArticle) => <p key={article.id}>{article.title}</p>) } <input type="text" onChange={(e: React.ChangeEvent) => { console.log('a', e); }} value={'a'} /> </div> ) } const Article: FC = () => { return ( <ArticleProvider name={'11'} style={{ color: 'red' }}> <h1>My Title</h1> <ShowArticles /> </ArticleProvider> ) }Copy the code

The react. FunctionComponent mentioned in the code has the children property built in, which can be found in the declaration file

// Props already has a PropsWithChildren type, built-in children Interface FunctionComponent<P = {}> {(props: PropsWithChildren<P>, context? : any): ReactElement<any, any> | null; } type PropsWithChildren<P> = P & { children? : ReactNode | undefined };Copy the code

Type declaration in props in hooks

  1. General component parameters:
type IProps = { message: string; count: number; disabled: boolean; /** Arrays of type string in two ways */ // names: string[]; names: Array<string>; / * * literal way of precise control, and can be used in a combined type, must be both in the a * / status: "waiting" | "success". */ obj: object; */ obj: object; } */ obj2: {};} */ obj2: {}; */ obj3: {id: string; title: string; }; /** Array of object types */ objArr: {id: string; title: string; } []; objAry: Array<{ id: string; title: string; }> /** An extensible object, attributes and attribute values need to meet the type requirements */ dict1: {[key: string]: MyTypeHere; }; dict2: Record<string, MyTypeHere>; / / same as dict1 / * * * don't do any operation can define Function/onSomething: Function; /** function with no arguments and return values */ onClick: () => void; / / onChange: (id: number) => void; / / onChange: (id: number) => void; /** onClick(event: react. MouseEvent<HTMLButtonElement>): void; /** Optional parameter */ optional? : OptionalType; };Copy the code
  1. Some special component parameters

Summary: Use react. ReactNode to define children

export interface AppProps { children1: JSX.Element; / / receive a JSX structure, there can be only one child children2: JSX. Element | JSX. Element []; // Can receive multiple child children3: React.ReactChildren; Children4: react.reactChild []; // React.ReactChild = React.ReactElement|React.ReactText -> React.ReactText=string|number children: React.ReactNode; / / it is best to use this in the statement to the children, contains ReactChild | ReactFragment | ReactPortal | Boolean | null | undefined functionChildren: (name: string) => React.ReactNode; // Receive a function that returns ReactNode style? : React.CSSProperties; // Receive the style attribute onChange? : React.FormEventHandler<HTMLInputElement>; // The onChange event is triggered. https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring // TODO Temporarily didn't know how to use props: perfect props & React.Com ponentPropsWithoutRef < "button" >; // to impersonate all the props of a button element and explicitly not forwarding its ref props2: Props & React.ComponentPropsWithRef<MyButtonWithForwardRef>; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref }Copy the code
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;

interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
Copy the code