TypeScript 3.0下react默认属性DefaultProps解决方案

ts和react的默认属性的四种解决方案

  • Non-null assertion operator(非空断言语句)
  • Component type casting(组件类型重置)
  • High order function for defining defaultProps(高阶组件)
  • Props getter function(Getter函数)

1、 非空断言语句

1、const color = this.props.color!;
2、this.props.onBlur ? this.props.onBlur(e): undefined;

2、组件类型重置

以通过匿名类创建组件,并将其分配给常量,我们将使用适当的道具类型将其转换为最终结果组件,同时保留实现中定义的所有“defaultProps”
image

3、高阶组件

globals.d.ts

declare type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

在uitls中定义withDefaultProps

export const withDefaultProps = <P extends object, DP extends Partial<P> = Partial<P>>(
  defaultProps: DP,
  Cmp: React.ComponentType<P>
) => {
  type RequiredProps = Omit<P, keyof DP>
  type Props = Partial<DP> & RequiredProps
  Cmp.defaultProps = defaultProps
  return (Cmp as React.ComponentType<any>) as React.ComponentType<Props>
}

说明

使用上面或者下面的实现都可以
image

input组件为一个完整的例子:

import classnames from 'classnames';
import * as React from 'react';
import { withDefaultProps } from '../utils';
import './style/input.styl';

const defaultProps = {
  type: 'text',
  value: '',
  disabled: false,
  readonly: false,
  maxlength: 60,
  placehololder: '',
  autofocus: false,
  autocomplete: '',
  clearable: false,
  passShow: false
}

type DefaultProps = Readonly<typeof defaultProps>;

type InputInnerProps = {
  prepend?: React.ReactNode;
  append?: React.ReactNode;
  className?: string;
  style?: React.CSSProperties;
  onChange?: (value: string) => void;
  onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
  onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
} & DefaultProps;

const InputState = {
  isFocus: false,
  inputValue: '',
  open: false
};

type State = Readonly<typeof InputState>;


const Input = withDefaultProps(
  defaultProps,
  class extends React.Component<InputInnerProps, State> {
    readonly state: State = InputState;
    private inputRef: React.RefObject<any> = React.createRef();
    getDerivedStateFromProps() {
      this.setState({
        open: this.props.passShow,
        inputValue: this.props.value
      })
    }

    private changeHander = (e: React.ChangeEvent<HTMLInputElement>):void => {
      this.setState({
        inputValue: e.target.value
      })
      this.props.onChange ? this.props.onChange(e.target.value) : undefined;
    }
    private handleFoucus = (e: React.FocusEvent<HTMLInputElement>):void => {
      this.props.onFocus ? this.props.onFocus(e): undefined;
      this.setState({
        isFocus: true
      })
    }
    private handleBlur = (e: React.FocusEvent<HTMLInputElement>):void => {
      this.props.onBlur ? this.props.onBlur(e): undefined;
      this.setState({
        isFocus: true
      })
    }
    private handleClear = ():void => {
      this.setState({
        inputValue: ''
      })
      this.inputRef.current.focus();
    }
    private handlePwdEye = ():void => {
      this.setState({
        open: !this.state.open
      })
    }
    public render() {
      const {
        type,
        disabled,
        readonly,
        autocomplete,
        autofocus,
        clearable,
        passShow,
        className,
        style,
        prepend,
        append,
        ...restProps
      } = this.props;
      const {
        isFocus,
        inputValue,
        open
      } = this.state;
      const inputCls = classnames('afo-input', className, {
        'afo-input--active': isFocus
      })
      const inputType:string = type === 'password' && passShow ? 'text': type;
      const showClear:boolean = clearable && inputValue && !readonly && !disabled ? true: false;
      const showPwdEye:boolean = type === 'password' && passShow && !disabled ? true: false;
      return (
        <div className={inputCls} style={style}>
          {
            prepend ? <div className="afo-input__prepend">{prepend}</div> : ''
          }
          <input
            className="afo-input__field"
            ref={this.inputRef}
            value={inputValue}
            {...restProps}
            type={inputType}
            disabled={disabled}
            readOnly={readonly}

            autoComplete={autocomplete}
            autoFocus={autofocus}
            onFocus={(e) => this.handleFoucus(e)}
            onBlur={(e) => this.handleBlur(e)}
            onChange={(e) => this.changeHander(e)}
          />
          {
            append || showClear || showPwdEye?
            <div className="afo-input__append">
              {
                showClear ? <div className="afo-input__clear"  onClick={() => this.handleClear()}>
                  <i className="afo-wrong" />
                </div> : ''
              }
              {
                showPwdEye ?
                <div className="afo-input__eye"  onClick={() => this.handlePwdEye()}>
                  <i className={open ? 'afo-inupt__eye--visible' : 'afo-inupt__eye--invisible'} />
                </div> : ''
              }
              {append}
            </div> :''
          }
        </div>
      )
    }
  }
)

export default Input;

4、Props getter function

条件类型映射的简陋工厂/闭包标识函数模式。

注意,我们使用了与withDefaultProps函数类似的类型映射构造,但我们不将defaultProps映射为可选的,因为它们在组件实现中是不可选的。

image
image
image

posted @ 2018-09-26 12:59  快乐~  阅读(9798)  评论(0编辑  收藏  举报