博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React & Redux in TypeScript - 静态类型指南
阅读量:4088 次
发布时间:2019-05-25

本文共 12414 字,大约阅读时间需要 41 分钟。

翻译自 ,作者:Piotrek Witek

翻译自 ,作责:Yusuke Mori

参考文章 

概述:最近在学习 react&TypeScript,发现有许多的组件模式和方法需要去梳理和总结。所以选择一些文章用于沉淀和思考,记录下一些知识点,和大家探讨。

publish:2019-03-21

目录:

  • 简介,环境配置()
  • React - 关键类型(react-redux-typescript-guide )
  • React - 组件模式(react-redux-typescript-guide & TypeScript 2.8下的终极React组件模式)
  • Redux - 使用以及 Redux Thunk 使用(TypeScriptでRedux Thunkを使う)
  • 总结

React - 关键类型

  • 展示性组件(FunctionComponent

    React.FunctionComponent<P> or React.FC<P>

    const MyComponent: React.FC<Props> = ...

  • 有状态组件(ClassComponent

    React.Component<P, S>

    class MyComponent extends React.Component<Props, State> { ...

  • 组件Props

    React.ComponentProps<typeof Component>

    获取组件(适用于ClassComponent、FunctionComponent)的Props的类型

    type MyComponentProps = React.ComponentProps<typeof MyComponent>;

  • React.FC | React.Component的联合类型

    React.ComponentType<P>

    123
    const withState = 

    ( WrappedComponent: React.ComponentType

    ,) => { ...

  • React 要素

    React.ReactElement<P> or JSX.Element

    表示React元素概念的类型 - DOM组件(例如

    )或用户定义的复合组件()

     

    const elementOnly: React.ReactElement = <div /> || <MyComponent />;

  • React Node

    React.ReactNode

    表示任何类型的React节点(基本上是ReactElement(包括Fragments和Portals)+ 原始JS类型 的合集)

    12
    const elementOrPrimitive: React.ReactNode = 'string' || 0 || false || null || undefined || 
    ||
    ;const Component = ({ children: React.ReactNode }) => ...
  • React CSS属性

    React.CSSProperties

    代表着Style Object在 JSX 文件中(通常用于 css-in-js)

    12
    const styles: React.CSSProperties = { flexDirection: 'row', ...const element = 
  • 通用的 React Event Handler

    React.ReactEventHandler<HTMLElement>

    123
    const handleChange: React.ReactEventHandler
    = (ev) => { ... }
  • 特殊的 React Event Handler

    React.MouseEvent<E> | React.KeyboardEvent<E> | React.TouchEvent<E>

    123
    const handleChange = (ev: React.MouseEvent
    ) => { ... }

React 组件模式

  • Function Components - FC 纯函数组件(无状态)

    顾名思义,纯函数组件本身不具备 State,所以没有状态,一切通过 Props

    12345678910111213141516171819202122
    import React, { FC, ReactElement, MouseEvent  } from 'react'type Props = {    label: string,    children: ReactElement,    onClick?: (e: MouseEvent
    ) => void}const FunctionComponent: FC
    = ({ label, children, onClick }: Props) => { return (
    {label}:
    )}export default FunctionComponent

    扩展属性(spread attributes)

    利用 ... 对剩余属性进行处理

    12345678910111213141516171819202122
    import React, { FC, ReactElement, MouseEvent, CSSProperties } from 'react'type Props = {    label: string,    children: ReactElement,    className?: string,    style?: CSSProperties,    onClick?: (e: MouseEvent
    ) => void,}const FunctionComponent: FC
    = ({ label, children, onClick, ...resetProps }: Props) => { return (
    {label}:
    )}export default FunctionComponent

    默认属性

    如果,需要默认属性,可以通过默认参数值来处理

    123456789101112131415161718192021
    import React, { FC, ReactElement, MouseEvent  } from 'react'type Props = {    label?: string,    children: ReactElement,}const FunctionComponent: FC
    = ({ label = 'Hello', children }: Props) => { return (
    {label}:
    )}export default FunctionComponent
  • Class Components

    相对于FC,多了 state,采用如下形式来定义Class Component

    这一部分的写法,与相同,觉得结构很清晰,复用。

    1234567891011121314151617181920212223242526272829303132333435363738
    import React, { Component } from 'react';type Props = {    label: string}const initialState  = {    count: 0}type State = Readonly
    class ClassCounter extends Component
    { readonly state: State = initialState private handleIncrement = () => this.setState(Increment) render() { const { handleIncrement } = this; const { label } = this.props; const { count } = this.state; return (
    {label}: {count}
    ) }}export const Increment = (preState: State) => ({ count: preState.count + 1 })export default ClassCounter

    默认属性

    处理 Class Component 的默认属性,主要有两种方法:

    • 一是定义高阶组件,例如中,利用 withDefaultProps 来定义默认属性,涉及组件的属性的类型转换;
    • 二是利用 static props 以及 componentWillReceiveProps,处理默认属性。

    具体业务中,视情况而定,第一中可以查看相关文章,这里介绍第二种

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
    import React, { Component } from 'react';type Props = {    label: string,    initialCount: number}type State = {    count: number;}class ClassCounter extends Component
    { static defaultProps = { initialCount: 1, } // 依据 defaultProps 对 state 进行处理 readonly state: State = { count: this.props.initialCount, } private handleIncrement = () => this.setState(Increment) // 响应 defaultProps 的变化 componentWillReceiveProps({ initialCount }: Props) { if (initialCount != null && initialCount !== this.props.initialCount) { this.setState({ count: initialCount }) } } render() { const { handleIncrement } = this; const { label } = this.props; const { count } = this.state; return (
    {label}: {count}
    ) }}export const Increment = (preState: State) => ({ count: preState.count + 1 })export default ClassCounter
  • 通用组件 Generic Components

    • 复用共有的逻辑创建组件
    • 常用于通用列表
    12345678910111213141516
    import React, { Component, ReactElement } from 'react'interface GenericListProps
    { items: T[], itemRenderer: (item: T, i: number) => ReactElement,}class GenericList
    extends Component
    , {}> { render() { const { items, itemRenderer } = this.props return
    {items.map(itemRenderer)}
    }}export default GenericList
  • Render Callback & Render Props

    • Render Callback,也被称为函数子组件,就是将 children 替换为 () => children;

    • Render Props,就是将 () => component 作为 Props 传递下去。

      1234567891011121314151617181920212223242526272829
      import React, { Component, ReactElement } from 'react';type Props = {    PropRender?: () => ReactElement,    children?: () => ReactElement}class PropRender extends Component
      { render() { const { props: { children, PropRender } }: { props: Props } = this; return (
      { PropRender && PropRender() } { children && children() }
      ) }}export default PropRender// 应用
      (

      Prop Render

      )} > { () => (

      Child Render

      ) }
  • HOC(Higher-Order Components)

    简单理解为,接受React组件作为输入,输出一个新的React组件的组件的工厂函数。

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546
    import * as React from 'react'interface InjectedProps {    label: string}export const withState = 
    ( BaseComponent: React.ComponentType
    ) => { type HocProps = BaseProps & InjectedProps & { initialCount?: number } type HocState = { readonly count: number } return class Hoc extends React.Component
    { // 方便 debugging in React-Dev-Tools static displayName = `withState(${BaseComponent.name})`; // 关联原始的 wrapped component static readonly WrappedComponent = BaseComponent; readonly state: HocState = { count: Number(this.props.initialCount) || 0, } handleIncrement = () => { this.setState({ count: this.state.count + 1 }) } render() { const { ...restProps } = this.props as any const { count } = this.state return ( <> {count}
    ) } }}

Redux - 使用以及 Redux Thunk 使用

以如下形式来介绍Redux,主要是in-ts的使用:

  • (prestate, action) => state;

  • 使用Redux Thunk 来出来异步操作。

    123456789101112131415
    // store.jstype DataType = {    counter: number}const DataState: DataType = {    counter: 0}type RootState = {    Data: DataType}export default RootState
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
    // action.jsimport { Action, AnyAction } from 'redux'import { ThunkAction, ThunkDispatch } from 'redux-thunk'import RootState from '../store/index'type IncrementPayload = {    value: number}interface IncrementAction extends Action {    type: 'INCREMENT',    payload: IncrementPayload}export const Increment = ({ value }: IncrementPayload): IncrementAction => {    const payload = { value }    return {        type: 'INCREMENT',        payload    }}export type DecrementPayload = {    value: number;};export interface DecrementAction extends Action {    type: 'DECREMENT';    payload: DecrementPayload;}export type RootAction = IncrementAction & DecrementAction;export const asyncIncrement = (    payload: IncrementPayload): ThunkAction
    , RootState, void, AnyAction> => { return async (dispatch: ThunkDispatch
    ): Promise
    => { return new Promise
    ((resolve) => { console.log('Login in progress') setTimeout(() => { dispatch(Increment(payload)) setTimeout(() => { resolve() }, 1000) }, 3000) }) }}
    123456789101112131415
    // reducer.jsimport { DataState, DataType } from '../store/Data'import { RootAction } from '../actions/'export default function (state: DataType = DataState, { type, payload }: RootAction): DataType {    switch(type) {        case 'INCREMENT':            return {                ...state,                counter: state.counter + payload.value,            };        default:            return state;    }}
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
    // Hearder.jsimport React, { Component, ReactNode } from 'react'import RootState from '../store/index'import { Dispatch, AnyAction } from 'redux'import { ThunkDispatch } from 'redux-thunk'import { connect } from 'react-redux'import { Increment, asyncIncrement } from '../actions/'const initialState = {    name: 'string'}type StateToPropsType = Readonly<{    counter: number}>type DispatchToPropsType = Readonly<{    handleAdd: () => void,    handleDec: () => void}>type StateType = Readonly
    type PropsType = { children?: ReactNode}type ComponentProps = StateToPropsType & DispatchToPropsType & PropsTypeclass Header extends Component
    { readonly state: StateType = initialState; render() { const { props: { handleAdd, handleDec, counter }, state: { name } } = this return (
    计数:{counter}
    ) } private handleClick = () => this.setState(sayHello);}const sayHello = (prevState: StateType) => ({ name: prevState.name + 'Hello world',})const mapStateToProps = (state: RootState, props: PropsType): StateToPropsType => { return { counter: state.Data.counter }}const mapDispatchToProps = (dispatch: ThunkDispatch
    ): DispatchToPropsType => { return { handleAdd: () => { dispatch(Increment({ value: 2 })) }, handleDec: async () => { dispatch(asyncIncrement({ value: 10 })) } }}export default connect
    (mapStateToProps, mapDispatchToProps)(Header)

  原文

转载地址:http://dyzii.baihongyu.com/

你可能感兴趣的文章
Android中AsyncTask的简单用法
查看>>
Jenkins 启动命令
查看>>
剑指offer算法题分析与整理(三)
查看>>
JVM并发机制探讨—内存模型、内存可见性和指令重排序
查看>>
WAV文件解析
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
QT打开项目提示no valid settings file could be found
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.182 - LeetCode1325 - C指针的魅力
查看>>
带WiringPi库的交叉笔译如何处理二之软链接概念
查看>>
Java8 HashMap集合解析
查看>>
自定义 select 下拉框 多选插件
查看>>
Linux常用统计命令之wc
查看>>
fastcgi_param 详解
查看>>
搞定Java面试中的数据结构问题
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
Winform多线程
查看>>
Spring AOP + Redis + 注解实现redis 分布式锁
查看>>