jtwang7 / React-Note

React 学习笔记
8 stars 2 forks source link

React 组件默认值及 TS 配置 #59

Open jtwang7 opened 1 year ago

jtwang7 commented 1 year ago

React 组件默认值及 TS 配置

React 组件默认值配置

React 组件字段 defaultProps 可以为 React 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况。 无论是 class component 还是 function component 都存在这个属性字段。

🌈 Class Component

type GreetProps = typeof Greet.defaultProps & {
  age: number;
};

class Greet extends React.Component<GreetProps> {
  static defaultProps = {
    age: 21,
  };
  /*...*/
}

// static 属性值可以被提到 class 外部,因此也可以写为:
Greet.defaultProps = { age:21 };

// Type-checks! No type assertions needed!
let el = <Greet age={3} />;

🌈 Function Component

// using typeof as a shortcut; note that it hoists!
// you can also declare the type of DefaultProps if you choose
// e.g. https://github.com/typescript-cheatsheets/react/issues/415#issuecomment-841223219
type GreetProps = { age: number } & typeof defaultProps;

const defaultProps = {
  age: 21,
};

const Greet = (props: GreetProps) => {
  // etc
};
Greet.defaultProps = defaultProps;

👋 goodBye defaultProps

根据 👉 这条推文defaultProps 最终将被弃用。目前的共识是使用对象默认值。

🌈 Class Component

type GreetProps = {
  age?: number;
};

class Greet extends React.Component<GreetProps> {
  render() {
    const { age = 21 } = this.props;
    /*...*/
  }
}

let el = <Greet age={3} />;

🌈 Function Component

type GreetProps = { age?: number };

const Greet = ({ age = 21 }: GreetProps) => // etc

深层 props 对象的默认赋值

对于简单的 props 对象,我们可以通过解构赋值。但对于深层嵌套对象而言,单层解构赋值会存在以下情况:

const {
  a = 4,
  b = {
    b1: 2,
    b2: {
      b2_1: true,
    }
  }
} = props;
// props -> 
// {
//   a: 5,
//   b: {
//    b1: 9,
//   }
// }

// b.b2 === undefined

b 默认属性赋值如上,但在传参过程中传递了 b: {b1: 5},则上面 b 属性就会被判别为已赋值,默认赋值的完整对象被覆盖。因此当我们访问 b.b2 时返回 undefined

🌈 对于深层嵌套对象,我们可以编写函数递归执行默认赋值,但通常情况下,我们可以声明一个 defaultProps 常量,在需要默认值判别处调用 defaultProps 内部的属性字段即可。

const defaultProps = {
  a: 4,
  b: {
    b1: 2,
    b2: {
      b2_1: true,
    }
  }
}

// props.b.b2 ?? defaultProps.b.b2

🔥 lodash.defaultsDeep

使用方法:默认项在后,目标项在前。目标项中已存在的字段不会被覆盖,目标项中未定义(undefined)的字段,将从后续项中取值填补,若存在多个后续项,则依次寻找字段填补直至遇到第一个可用值为止。

const default = {
  cell: {
    width: 10,
    height: 10,
    color: "summer",
  },
  font: {
    size: 10,
    weight: "normal",
  },
  padding: [20, 20, 20, 20],
  needTopBar: false,
  needRightBar: false,
  needColorBar: true,
}
_.defaultsDeep(options, default)

👉 注意:不要将 React Component props 直接应用于 _.defaultsDeep() 函数,这将不起作用,原因未知。为 React props 赋予深层默认值的方法如下:

const p = useMemo(() => (_.cloneDeep(props)), [props]); // 深拷贝 props 对象
const target = useMemo(() => (_.defaultsDeep(p, { ... })), [p]); // 对副本进行默认赋值

👋 lodash.defaultsDeep 函数默认赋值存在的问题

lodash.defaultsDeep 会递归进行默认赋值,但当递归的元素为数组时,该函数会遍历数组内的各个元素。假如传参中嵌套数组的长度与默认对象嵌套数组长度不同,则结果是合并而非替换。

const a = {
  data: [1, 2, 3]
}
const b= {
  data: [5, 6, 7, 8, 9]
}
_.defaultsDeep(a, b)
// {data: [1, 2, 3, 8, 9]}