使用typeScript开发React的最佳实战可以参考这里:https://react-typescript-cheatsheet.netlify.app/docs/basic/setup

开发

组件的Props

基础类型、对象类型、函数类型

  1. type AppProps = {
  2. message: string;
  3. count: number;
  4. disabled: boolean;
  5. /** array of a type! */
  6. names: string[];
  7. /** string literals to specify exact string values, with a union type to join them together */
  8. status: "waiting" | "success";
  9. /** any object as long as you dont use its properties (NOT COMMON but useful as placeholder) */
  10. obj: object;
  11. obj2: {}; // almost the same as `object`, exactly the same as `Object`
  12. /** an object with any number of properties (PREFERRED) */
  13. obj3: {
  14. id: string;
  15. title: string;
  16. };
  17. /** array of objects! (common) */
  18. objArr: {
  19. id: string;
  20. title: string;
  21. }[];
  22. /** a dict object with any number of properties of the same type */
  23. dict1: {
  24. [key: string]: MyTypeHere;
  25. };
  26. dict2: Record<string, MyTypeHere>; // equivalent to dict1
  27. /** any function as long as you don't invoke it (not recommended) */
  28. onSomething: Function;
  29. /** function that doesn't take or return anything (VERY COMMON) */
  30. onClick: () => void;
  31. /** function with named prop (VERY COMMON) */
  32. onChange: (id: number) => void;
  33. /** alternative function type syntax that takes an event (VERY COMMON) */
  34. onClick(event: React.MouseEvent<HTMLButtonElement>): void;
  35. /** an optional prop (VERY COMMON!) */
  36. optional?: OptionalType;
  37. };

React相关的类型

  1. export declare interface AppProps {
  2. children1: JSX.Element; // bad, doesnt account for arrays
  3. children2: JSX.Element | JSX.Element[]; // meh, doesn't accept strings
  4. children3: React.ReactChildren; // despite the name, not at all an appropriate type; it is a utility
  5. children4: React.ReactChild[]; // better, accepts array children
  6. children: React.ReactNode; // best, accepts everything (see edge case below)
  7. functionChildren: (name: string) => React.ReactNode; // recommended function as a child render prop type
  8. style?: React.CSSProperties; // to pass through style props
  9. onChange?: React.FormEventHandler<HTMLInputElement>; // form events! the generic parameter is the type of event.target
  10. // more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring
  11. props: Props & React.ComponentPropsWithoutRef<"button">; // to impersonate all the props of a button element and explicitly not forwarding its ref
  12. props2: Props & React.ComponentPropsWithRef<MyButtonWithForwardRef>; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref
  13. }

函数式组件

最简单的

  1. interface AppProps = { message: string };
  2. const App = ({ message }: AppProps) => <div>{message}</div>;

包含children的

利用内置的React.FC 内置的类型的话,除了包含定义的Props还会自动的增加一个children类型。

  1. // 等同于
  2. AppProps & {
  3. children: React.ReactNode
  4. propTypes?: WeakValidationMap<P>;
  5. contextTypes?: ValidationMap<any>;
  6. defaultProps?: Partial<P>;
  7. displayName?: string;
  8. }
  9. // 使用
  10. interface AppProps = { message: string };
  11. const App: React.FC<AppProps> = ({ message, children }) => {
  12. return (
  13. <>
  14. {children}
  15. <div>{message}</div>
  16. </>
  17. )
  18. };

Hooks

useState

默认值可以说明类型,不用手动说明交给ts自动推断即可

  1. // val: boolean
  2. const [val, toggle] = React.useState(false);
  3. toggle(false)
  4. toggle(true)

初始值是null或者是undefined

  1. const [user, setUser] = React.useState<IUser | null>(null);
  2. // later...
  3. setUser(newUser);

useReducer

用联合类型(Discriminated Unions)来标注 Action 的类型

  1. const initialState = { count: 0 };
  2. type ACTIONTYPE =
  3. | { type: "increment"; payload: number }
  4. | { type: "decrement"; payload: string };
  5. function reducer(state: typeof initialState, action: ACTIONTYPE) {
  6. switch (action.type) {
  7. case "increment":
  8. return { count: state.count + action.payload };
  9. case "decrement":
  10. return { count: state.count - Number(action.payload) };
  11. default:
  12. throw new Error();
  13. }
  14. }
  15. function Counter() {
  16. const [state, dispatch] = React.useReducer(reducer, initialState);
  17. return (
  18. <>
  19. Count: {state.count}
  20. <button onClick={() => dispatch({ type: "decrement", payload: "5" })}>
  21. -
  22. </button>
  23. <button onClick={() => dispatch({ type: "increment", payload: 5 })}>
  24. +
  25. </button>
  26. </>
  27. );
  28. }

传入特定的type时,剩下的类型payload就会自动匹配推断。

useEffect

useEffect的返回值需要是一个方法或者是undefined,可以用自执行函数

  1. useEffect(() => {
  2. (async () => {
  3. const user = await getUser()
  4. setUser(user)
  5. })()
  6. }, [])

useRef

去公众号文章看

useImperativeHandle

去公众号文章看

自定义hook

  1. export function useLoading() {
  2. const [isLoading, setState] = React.useState(false);
  3. const load = (aPromise: Promise<any>) => {
  4. setState(true);
  5. return aPromise.finally(() => setState(false));
  6. };
  7. // ✅ 加了 as const 会推断出 [boolean, typeof load]
  8. // ❌ 否则会是 (boolean | typeof load)[]
  9. return [isLoading, load] as const;[]
  10. }

如果写了库,需要把类型最终导出出来。

React API

forwardRef

子组件

  1. type Props = { };
  2. export type Ref = HTMLButtonElement;
  3. export const FancyButton = React.forwardRef<Ref, Props>((props, ref) => (
  4. <button ref={ref} className="MyClassName">
  5. {props.children}
  6. </button>
  7. ));

父组件使用,将ref转发给button

  1. export const App = () => {
  2. const ref = useRef<HTMLButtonElement>()
  3. return (
  4. <FancyButton ref={ref} />
  5. )
  6. }

事件

input的onChange

  1. const ColorSelectInput: React.FC<{}> = () => {
  2. const [color, setColor] = React.useState<string>("blue")
  3. //定义事件changeColor
  4. const changColor = (e: React.ChangeEvent<HTMLInputElement>) => {
  5. setColor(e.target.value)
  6. //input中onChange调用changeColor
  7. }
  8. return <input value={color} onChange={changColor}/>
  9. }

相关文章