React - defaultProps vs ES6默认params在解构时(性能问题)

Vad*_*est 39 performance destructuring ecmascript-6 reactjs

在我的一个无状态功能组件中设置默认值时,我刚刚遇到了关于React性能的问题.

这个组件有一个defaultProps定义的row: false,但我不喜欢它,因为defaultProps位于文件的末尾,这实际上使它更难看.因此,我们不知道默认属性.所以我直接将它移动到函数声明中,并使用参数的ES6默认值进行分配.

const FormField = ({
  row = false,
  ...others,
}) => {
  // logic...
};
Run Code Online (Sandbox Code Playgroud)

但后来我们与一位同事争论这是一个好主意.因为这样做可能看起来微不足道,但也可能对性能产生很大影响,因为反应不知道默认值.

我相信在这种情况下,它是微不足道的.因为它是布尔值而不是对象/数组,因此在对帐期间不会被视为不同的值.


但是,让我们现在看一个更高级的用例:

const FormField = ({
  input: { name, value, ...inputRest },
  label = capitalize(name),
  placeholder = label,
  row = false,
  meta: { touched, error, warning },
  ...others,
}) => {
  // logic...
};
Run Code Online (Sandbox Code Playgroud)

在这里,我基于placeholderfrom 的值label,它本身就是基于的input.name.使用ES6解构和参数的默认值使整个事情很容易编写/理解,它就像一个魅力.

但这是个好主意吗?如果没有,那么你会怎么做呢?

Vad*_*est 27

我在Discord #reactiflux频道与几个人交谈,实际上得到了我想要的答案.

基本上有三个使用React组件的用例,在其中一些中,解构参数会影响性能,因此了解正在发生的事情是很重要的.

无状态功能组件

const MyComponent = ({ name = 'John Doe', displayName = humanize(name), address = helper.getDefaultAddress() }) => {
  return (
    <div>{displayName}</div>
  );
};
Run Code Online (Sandbox Code Playgroud)

这是一个无状态的功能组件.没有状态,它是功能性的,因为它不是一个Class实例,而是一个简单的功能.

在这种情况下,没有生命周期,你不能有一个componentWillMountshouldComponentUpdateconstructor有.而且由于没有对生命周期的管理,因此对性能没有任何影响.此代码完全有效.有些人可能更喜欢处理displayName函数体内的默认值,但最终它并不重要,它不会影响性能.

无状态的非功能组件

(不要这样做!)

class MyComponent extends React.Component {
    render() {
        const { name = 'John Doe', displayName = humanize(name), address = helper.getDefaultAddress() } = this.props;
        return (
            <div>{displayName}</div>
          );
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个无状态的非功能组件.没有国家,但它不是"功能性",因为它是一个class.因为它是一个类,扩展React.Component,这意味着你将有一个生命周期.你可以有componentWillMountshouldComponentUpdateconstructor有.

而且,因为它有一个生命周期,所以编写这个组件的方式很糟糕.但为什么?

简单地说,React提供了一个defaultProps属性,用于处理默认的道具值.在处理非功能组件时,最好使用它,因为所有依赖的方法都会调用它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(),
};
Run Code Online (Sandbox Code Playgroud)

这个更好.因为名称将始终是John Doe未定义的.address默认值也处理了,但不是displayName......为什么?

好吧,我还没有找到解决这个特殊用例的方法.因为displayName应该基于name属性,我们在定义时无法访问(AFAIK)defaultProps.我看到的唯一方法是render直接在方法中处理它.也许有更好的方法.

我们没有这个address属性的问题,因为它不是基于MyComponent属性,而是依赖于完全独立的东西,不需要道具.

有状态的非功能组件

它与"无状态非功能组件"完全相同.因为仍然存在生命周期,所以行为将是相同的.state组件中有一个额外的内部的事实不会改变任何东西.


我希望这有助于理解何时使用组件解构.我真的很喜欢这种功能性的方式,它更清洁恕我直言(+1为简单).

您可能更喜欢始终使用defaultProps,无论是使用功能组件还是非功能组件,它都是有效的.(+1表示一致性)

只要注意"需要"使用的非功能性组件的生命周期defaultProps.但最终选择总是你的;)

  • @Vadorequest现在已经很高兴看到这个答案的更新,因为在React中引入了钩子。 (3认同)
  • @LazarLjubenović /sf/answers/3951016891/ tl;dr defaultProps 对于新的有状态功能组件将被弃用:) (3认同)
  • 我认为持有可以从其他道具衍生的道具是一种不好的做法。`displayName` 仅在显示时使用(即在 `render` 函数中)。这应该是它的范围。 (2认同)
  • 因为“defaultProps”和类已被弃用,有利于功能组件(没有钩子),所以这个答案不像以前那么有用。但是,如果您使用基于类的组件,它仍然是准确的。 (2认同)

DSa*_*Sav 5

和默认函数参数之间的一个很大的区别defaultProps是前者将根据 propTypes 检查。eslint-plugin-reactrequire-default-props的规则很好地解释了这一点。

defaultProps与代码中的自定义默认逻辑相比,优点之一是在类型检查发生defaultProps之前由 React 解析PropTypes,因此类型检查也适用于您的defaultProps. 对于无状态函数组件也是如此:默认函数参数的行为不一样defaultProps,因此defaultProps仍然首选使用。