我在 Discord #reactiflux 频道上与几个人交谈,实际上得到了我想要的答案。
React 组件基本上有三个用例,在其中一些用例中,解构参数会影响性能,因此了解幕后发生的事情很重要。
无状态功能组件
const MyComponent = ({ name = 'John Doe', displayName = humanize(name), address = helper.getDefaultAddress() }) => {
return (
<div>{displayName}</div>
);
};
这是一个无状态的功能组件。没有状态,它是函数式的,因为它不是一个Class实例,而是一个简单的函数。
在这种情况下,没有生命周期,你不能有componentWillMountorshouldComponentUpdate或constructorthere。并且因为没有生命周期的管理,所以对性能没有任何影响。这段代码是完全有效的。有些人可能更喜欢displayName在函数体内处理默认值,但最终这并不重要,它不会影响性能。
无状态非功能组件
(不要这样做!)
class MyComponent extends React.Component {
render() {
const { name = 'John Doe', displayName = humanize(name), address = helper.getDefaultAddress() } = this.props;
return (
<div>{displayName}</div>
);
}
}
这是一个无状态的非功能组件。没有状态,但它不是“功能性的”,因为它是一个class. 并且因为它是一个类,所以扩展React.Component,这意味着您将拥有一个生命周期。你可以有componentWillMount或shouldComponentUpdate或constructor有。
而且,因为它有一个生命周期,这个组件的编写方式是不好的。但为什么?
简单地说,React 提供了一个defaultProps属性来处理默认的 props 值。而且在处理非功能性组件时实际上使用它会更好,因为它会被所有依赖this.props.
前面的代码片段创建了名为nameand 的新局部变量displayName,但默认值仅适用于该render方法!. 如果您希望为每个方法应用默认值,例如来自 React 生命周期的那些(shouldComponentUpdate等),那么您必须使用defaultProps代替。
所以,前面的代码实际上是一个错误,可能会导致对 的默认值产生误解name。
这是它应该如何编写,以获得相同的行为:
class MyComponent extends React.Component {
render() {
const { name, displayName = humanize(name), address } = this.props;
return (
<div>{displayName}</div>
);
}
}
MyComponent.defaultProps = {
name: 'John Doe',
address: helper.getDefaultAddress(),
};
这个更好。因为John Doe如果未定义,名称将始终存在。address默认值也被处理了,但没有displayName......为什么?
好吧,我还没有找到解决这个特殊用例的方法。因为displayName应该基于name属性,我们在定义时无法访问(AFAIK)defaultProps。我看到的唯一方法是render直接在方法中处理它。也许有更好的方法。
我们的address属性没有这个问题,因为它不是基于 MyComponent 属性,而是依赖于不需要props的完全独立的东西。
有状态的非功能组件
它的工作原理与“无状态非功能组件”完全相同。因为仍然存在生命周期,所以行为将是相同的。state组件中有一个额外的内部结构这一事实不会改变任何东西。
我希望这有助于理解在对组件使用解构时。我真的很喜欢功能方式,恕我直言,它更干净(为简单起见,+1)。
您可能更喜欢始终使用defaultProps,无论是使用功能组件还是非功能组件,它也是有效的。(+1 一致性)
请注意“需要”使用defaultProps. 但最终选择总是你的;)
编辑 10-2019:defaultProps 最终将在未来某个时候从 React API 中删除,请参阅https://stackoverflow.com/a/56443098/2391795和https://github.com/reactjs/rfcs/pull/107对于 RFC。