Typescript-React Cheatsheet2020-05-27 22:57Dev, JavaScript, Typescript, React, Cheatsheet

References

Frequently Used

Function Components

FC 必须要返回 JSX, 不能返回其他类型

Quick Snippet

type AppProps = {message: string}; /* could also use interface */

// Type 1
const App = ({message}: AppProps) => <div>{message}</div>;

// Type 2
const App: React.FC<{message: string}> = ({ message }) => (
  <div>{message}</div>
);

// Type 3
const App: React.FunctionComponent<{message: string}> = ({ message }) => (
  <div>{message}</div>
);

Full Example

export interface LiquidDatePickerInput extends InputBaseProps {
  selected?: Date
  onChange?: (date: any) => void
}

const DatePicker: React.FC<DatePickerInput> = props => (
  <DatePicker
    {...props}
  />
)

Convert other HTML to JSX

有些时候需要用一些奇怪的方法试着一堆 HTML, 如果希望 react 做这样的操作,那么就要进行转换

这是一个临时的 Solution

See commentary by @ferdaber here.

const MyArrayComponent = () => (Array(5).fill(<div />) as any) as JSX.Element;

Hooks

useState

// Hooks 也可以设置类型, 但是因为会有一个空值所以需要使 Union Type
const [user, setUser] = React.useState<IUser | null>(null);

// newUser 必须是 IUser 的类型
setUser(newUser);

useRef

function TextInputWithFocusButton() {

  // initialise with null, but tell TypeScript we are looking for an HTMLInputElement
  // HTMLInputElement 类型非常重要
  const inputEl = React.useRef<HTMLInputElement>(null);

  const onButtonClick = () => {
    // null check
    if (inputEl && inputEl?.current) {
      inputEl.current.focus();
    }
  };
  return (
    <>
      {/* inputEl 设置了仅仅针对 HTMLInputElement 类型, 因此只能给 input 使用 */}
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useReducer

type AppState = {};
type Action =
  | {type: "SET_ONE"; payload: string}
  | {type: "SET_TWO"; payload: number};

export function reducer(state: AppState, action: Action): AppState {
  switch (action.type) {
    case "SET_ONE":
      return {
        ...state,
        one: action.payload, // `payload` is string
      };
    case "SET_TWO":
      return {
        ...state,
        two: action.payload, // `payload` is number
      };
    default:
      return state;
  }
}

Custom Hooks

export function useLoading() {
  const [isLoading, setState] = React.useState(false);
  const load = (aPromise: Promise<any>) => {
    setState(true);
    return aPromise.finally(() => setState(false));
  };
  return [isLoading, load] as const; // infers [boolean, typeof load] instead of (boolean | typeof load)[]
}

Class Components

Standard Class Component

/* 这些接口加上 可以同时 export 出去以方便后期复用 */
type MyProps = {
  // using `interface` is also ok
  message: string;
};

type MyState = {
  count: number; // like this
};
class App extends React.Component<MyProps, MyState> {
  state: MyState = {
    // optional second annotation for better type inference
    count: 0,
  };

  pointer: number;

  componentDidMount() {
    this.pointer = 3;
  }

  render() {
    return (
      <div onClick={() => this.increment(1)}>
        {this.props.message} {/* props */}
        {this.state.count} {/* states */}
        {this.pointer} {/* attrs */}
      </div>
    );
  }
  increment = (amt: number) => {
    // like this
    this.setState((state) => ({
      count: state.count + amt,
    }));
  };

}

Examples: Basic Prop Types + React Prop Type

type AppProps = {
  message: string;
  count: number;
  disabled: boolean;
  /** array of a type! */
  names: string[];
  /** string literals to specify exact string values, with a union type to join them together */
  status: "waiting" | "success";
  /** any object as long as you dont use its properties (not common) */
  obj: object;
  obj2: {}; // almost the same as `object` , exactly the same as `Object`
  /** an object with defined properties (preferred) */
  obj3: {
    id: string;
    title: string;
  };
  /** array of objects! (common) */
  objArr: {
    id: string;
    title: string;
  }[];
  /** any function as long as you don't invoke it (not recommended) */
  onSomething: Function;
  /** function that doesn't take or return anything (VERY COMMON) */
  onClick: () => void;
  /** function with named prop (VERY COMMON) */
  onChange: (id: number) => void;
  /** alternative function type syntax that takes an event (VERY COMMON) */
  onClick(event: React.MouseEvent<HTMLButtonElement>): void;
  /** an optional prop (VERY COMMON!) */
  optional?: OptionalType;
};

export declare interface AppProps {
  children1: JSX.Element; // bad, doesnt account for arrays
  children2: JSX.Element | JSX.Element[]; // meh, doesn't accept strings
  children3: React.ReactChildren; // despite the name, not at all an appropriate type; it is a utility
  children4: React.ReactChild[]; // better
  children: React.ReactNode; // best, accepts everything
  functionChildren: (name: string) => React.ReactNode; // recommended function as a child render prop type
  style?: React.CSSProperties; // to pass through style props
  onChange?: React.FormEventHandler<HTMLInputElement>; // form events! the generic parameter is the type of event.target
  props: Props & React.PropsWithoutRef<JSX.IntrinsicElements["button"]>; // to impersonate all the props of a button element without its ref
}

/**
JSX.Element -> Return value of React.createElement
React.ReactNode -> Return value of a component
*/

Forms and Events

Inline Event

onClick Event

const el = (
  <button
    onClick={(event) => {
      /* ... */
    }}
  />
);

Uncontrolled Form Event

<form
  ref={formRef}
  onSubmit={(e: React.SyntheticEvent) => { // 写的时候需要注意这边参数的 type
    e.preventDefault();
    const target = e.target as typeof e.target & {
      email: {value: string};
      password: {value: string};
    };
    const email = target.email.value; // typechecks!
    const password = target.password.value; // typechecks!
    // etc...
  }}
>
  <div>
    <label>
      Email:
      <input type="email" name="email" />
    </label>
  </div>
  <div>
    <label>
      Password:
      <input type="password" name="password" />
    </label>
  </div>
  <div>
    <input type="submit" value="Log in" />
  </div>
</form>

Event Types


onChange = (e: React.FormEvent<HTMLInputElement>): void => {
  this.setState({text: e.currentTarget.value});
};

// 下面这种方法也可以,这是两种不同的 typecheck

onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
  this.setState({text: e.currentTarget.value})
}

render() {
  return (
    <div>
      <input type="text" value={this.state.text} onChange={this.onChange} />
    </div>
  );
}

TODO: https://github.com/typescript-cheatsheets/react-typescript-cheatsheet#context

Powered by Remix
|
Designed by szhshp
|
Copyright © szhshp 2022