相应版本
"react": "^18.2.0"、"typescript": "^4.9.3"
前置知识
类型推断(Type Inference)
let x = 3;
即使不声明也会类型推断为
number类型
再赋值为
string类型会报错
函数组件声明
接口类型
interface AppProps {
message: string;
}
不需要children Props
// 通过类型推断返回值JSX.Element
export const App = ({ message }: AppProps) => {
return <div>{message}</div>;
};
需要children Props
type PropsWithChildren<P = unknown> = P & { children?: ReactNode | undefined };
import { PropsWithChildren } from 'react';
// 通过类型推断返回值JSX.Element
export const AppWithChildren = ({ message, children }: PropsWithChildren<AppProps>) => {
return (
<div>
<div>{message}</div>
<div>{children}</div>
</div>
);
};
Hook
useState
接口类型
// index.d.ts
type SetStateAction<S> = S | ((prevState: S) => S);
type Dispatch<A> = (value: A) => void;
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
使用
import { useState } from 'react';
interface User {
name: string;
age: number;
}
const App = () => {
// 空值推断
// useState<undefined>(): [undefined, React.Dispatch<React.SetStateAction<undefined>>]
const [undefinedVal1, setUndefinedVal1] = useState();
// 类型推断
// useState<undefined>(initialState: (() => undefined) | undefined): [undefined, React.Dispatch<React.SetStateAction<undefined>>]
const [undefinedVal2, setUndefinedVal2] = useState(undefined);
// useState<null>(initialState: (() => null) | null): [null, React.Dispatch<React.SetStateAction<null>>]
const [nullVal, setNullVal] = useState(null);
// 声明类型-赋值为空
// useState<number>(): [number | undefined, React.Dispatch<React.SetStateAction<number | undefined>>]
const [val, setVal] = useState<number>();
// 推荐声明方式
const [user1, setUser1] = useState<User | null>(null);
const [user2, setUser2] = useState<User>({} as User);
const usageOfUserData = () => {
console.log(user1?.age);
console.log(user2.age);
};
return (
<div>
<div>test</div>
</div>
);
};
export default App;
useRef
接口类型
interface RefObject<T> {
readonly current: T | null;
}
interface MutableRefObject<T> {
current: T;
}
function useRef<T>(initialValue: T|null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
使用
import { useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
// App1
// dom ref
export const App1 = () => {
// useRef<HTMLInputElement>(initialValue: HTMLInputElement | null): React.RefObject<HTMLInputElement>
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return <input ref={inputRef} type="text" />;
};
// App2
// dom forwardRef
export const App2 = () => {
// useRef<HTMLInputElement>(initialValue: HTMLInputElement | null): React.RefObject<HTMLInputElement>
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return (
<div className="App">
<ForwardRefMyInput ref={inputRef} />
</div>
);
};
const ForwardRefMyInput = forwardRef<HTMLInputElement>((props, ref) => {
return <input {...props} ref={ref} type="text" />;
});
// App3 useImperativeHandle
type CountdownHandleRef = {
start: () => void;
};
export const App3 = () => {
// useRef<CountdownHandleRef>(initialValue: CountdownHandleRef | null): React.RefObject<CountdownHandleRef>
const countdownEl = useRef<CountdownHandleRef>(null);
useEffect(() => {
countdownEl.current?.start();
}, []);
return <Countdown ref={countdownEl} />;
};
const Countdown = forwardRef<CountdownHandleRef>((...[, ref]) => {
useImperativeHandle(ref, () => ({
start() {
console.log('Start');
},
}));
return <div>Countdown</div>;
});
// App4 获取最新值
export const App4 = () => {
// useRef<number>(initialValue: number): React.MutableRefObject<number>
const intervalRef = useRef<number>(0);
useEffect(() => {
const timer = setInterval(() => {
intervalRef.current++;
}, 1000);
return () => clearInterval(timer);
}, []);
const getTempVal = () => {
console.log(intervalRef.current);
};
return (
<div>
<button onClick={getTempVal}>getTempVal</button>
</div>
);
};
useCallBack
接口类型
type DependencyList = ReadonlyArray<unknown>;
function useCallback<T extends Function>(callback: T, deps: DependencyList): T;
使用
import { useCallback, useState } from 'react';
export const App = () => {
const [callBackDeps] = useState<number>(0);
const memoizedCallback = useCallback<(param1: string, param2: number) => { test: number }>(
(param1, param2) => {
console.log(param1, param2);
return { test: param2 };
},
[callBackDeps],
);
return (
<div>
<button onClick={() => memoizedCallback('test', 111)}></button>
</div>
);
};
useMemo
接口类型
function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;
使用
import { useMemo, useState } from 'react';
interface CalcResult {
val: number;
}
export const App1 = () => {
const [memoDeps] = useState<number>(0);
const computedVal = useMemo<CalcResult>(() => {
return { val: memoDeps };
}, [memoDeps]);
return (
<div>
<div>{computedVal.val}</div>
</div>
);
};
useEffect
接口类型
declare const UNDEFINED_VOID_ONLY: unique symbol;
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
type EffectCallback = () => (void | Destructor);
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
不支持泛型
使用
import { useEffect, useState } from 'react';
export const App1 = () => {
const [effectDep] = useState<number>(0);
useEffect(() => {
console.log('test...');
}, [effectDep]);
useEffect(() => {
const timer = setInterval(() => {
console.log('test.......');
}, 1000);
return () => clearInterval(timer);
}, []);
return (
<div>
<div>useEffect</div>
</div>
);
};
useLayoutEffect
和useEffect接口定义一致
接口定义
declare const UNDEFINED_VOID_ONLY: unique symbol;
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
type EffectCallback = () => (void | Destructor);
function useLayoutEffect(effect: EffectCallback, deps?: DependencyList): void;
使用
import { useLayoutEffect, useState } from 'react';
export const App1 = () => {
const [effectDep] = useState<number>(0);
useLayoutEffect(() => {
console.log('test...');
}, [effectDep]);
useLayoutEffect(() => {
const timer = setInterval(() => {
console.log('test.......');
}, 1000);
return () => clearInterval(timer);
}, []);
return (
<div>
<div>useLayoutEffect</div>
</div>
);
};
uesContext
接口类型
type WeakValidationMap<T> = {
[K in keyof T]?: null extends T[K]
? Validator<T[K] | null | undefined>
: undefined extends T[K]
? Validator<T[K] | null | undefined>
: Validator<T[K]>
};
interface ExoticComponent<P = {}> {
(props: P): (ReactElement|null);
readonly $$typeof: symbol;
}
interface ProviderExoticComponent<P> extends ExoticComponent<P> {
propTypes?: WeakValidationMap<P> | undefined;
}
interface ProviderProps<T> {
value: T;
children?: ReactNode | undefined;
}
interface ConsumerProps<T> {
children: (value: T) => ReactNode;
}
type Provider<T> = ProviderExoticComponent<ProviderProps<T>>;
type Consumer<T> = ExoticComponent<ConsumerProps<T>>;
interface Context<T> {
Provider: Provider<T>;
Consumer: Consumer<T>;
displayName?: string | undefined;
}
function createContext<T>(
defaultValue: T,
): Context<T>;
使用
import { createContext, useContext } from 'react';
interface User {
name: string;
age: number;
}
const UserContext = createContext<User | null>(null);
export const App1 = () => {
return (
<UserContext.Provider value={{ name: 'test', age: 19 }}>
<SonApp />
</UserContext.Provider>
);
};
const SonApp = () => {
const context = useContext(UserContext);
return <div>{context?.age}</div>;
};
useReducer
接口类型
type Dispatch<A> = (value: A) => void;
type Reducer<S, A> = (prevState: S, action: A) => S;
type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;
type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;
function useReducer<R extends Reducer<any, any>>(
reducer: R,
initialState: ReducerState<R>,
initializer?: undefined
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
应用
import { useReducer } from 'react';
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() {
// 定义好reducer后通过类型推断可得到state、dispatch类型
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement', payload: '5' })}>-</button>
<button onClick={() => dispatch({ type: 'increment', payload: 5 })}>+</button>
</>
);
}
事件相关
import { ChangeEvent, FocusEvent } from 'react';
export const App1 = () => {
const onchangeEvent = (e: ChangeEvent<HTMLInputElement>) => {
console.log('onchangeEvent::', e);
console.log('onchangeEvent.target::', e.target.value);
};
const onBlurEvent = (e: FocusEvent<HTMLInputElement>) => {
console.log('onBlurEvent::', e);
console.log('onBlurEvent:target::', e.target.value);
};
return (
<div>
<input onChange={onchangeEvent} onBlur={onBlurEvent} />
</div>
);
};