React: ES6 类语法中的默认道具

创建于 2015-04-22  ·  40评论  ·  资料来源: facebook/react

ES6 支持公告说:

指定类状态的惯用方法是只使用一个简单的实例属性。 同样, getDefaultProps 和 propTypes 实际上只是构造函数上的属性。

这对我来说很有意义,但我注意到一些可能值得重新思考的小不一致。

当使用原始的.createClass语法时, getDefaultProps返回的值似乎在组件生命周期的其他点使用——而不仅仅是在构造函数中。 例如,如果我检查发送到componentWillReceiveProps(props) ,我可以看到应用了默认道具。

这_不_似乎是使用 ES6 类语法时的情况,这意味着我必须复制代码。 这是我的意思的一个例子:

class Control extends React.Component {

  constructor(props) {
    props.value = props.value || '';
    super(props);
  }

  // ...

  componentWillReceiveProps(props) {
    props.value = props.value || '';
    // Do something with props...
  }

}

如您所见,我正在复制表达式props.value = props.value || '' 。 如果我有不止一个默认值,我显然会有更多的重复。

使用.createClass方法时,我可以从getDefaultProps方法返回{value: ''} ,这会起作用,而且我只需要执行一次。

恢复此方法以避免不必要的重复是否有意义? 还有另一种我不知道的更像 React 的方法吗?

最有用的评论

没错。 相反,你写这个:

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

那对你有用吗?

所有40条评论

调用 componentWillReceiveProps 时应该已经合并了默认道具。

调用 componentWillReceiveProps 时应该已经合并了默认道具。

据我所知,使用 ES6 类语法时永远不会调用getDefaultProps

没错。 相反,你写这个:

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

那对你有用吗?

啊,抱歉,我现在在文档中看到了。 谢谢!

因为我是从 Google 搜索到这里的,而且我更喜欢class来封装我的代码,所以可以使用计算属性设置默认道具,如下所示:

import React, {Component, PropTypes} from 'react'
class DefaultPropsExample extends Component {
  static defaultProps = {
    ...Component.defaultProps,
    instructions: 'Usage instructions not provided.',
  }
}

@jhabdas我猜你给出的不是 ES2015 语法; 如果我使用静态道具,Babel 会抛出意外的令牌,但是,对于那些在 es2015 中像我一样工作的人,这是一个有效的东西。

import React from 'react';
export default class extends React.Component {

  static get defaultProps() {
    return {
      // stuff you want :)
    }
  }

}

更新

安装@zpao的链接后,我可以使用静态属性...

@Gopikrishna19您需要启用另一个实现类属性提议的 babel 插件: http ://babeljs.io/docs/plugins/transform-class-properties/

@zpao哦! 今天的另一个新东西:) 会尝试的,非常感谢!

@Gopikrishna19我真的很喜欢你发布的代码片段 b/c 我可以在初始化默认道具之前做一些预处理。 谢谢你提到它。

这似乎有效,在我看来它更优雅:

....

 static defaultProps = {
      //someDefaultProps
  };

  constructor(props, defaultProps) {
    super(props, defaultProps);
  }

....

@fxhereng第二个参数是为context保留的,所以我会避免用一些自定义含义覆盖它,因为这可能会在未来的版本中中断。

好的@gaearon为您设置默认道具的最佳方法是什么?

谢谢,

对此的推荐方法是什么?

如果您使用实验性转换http://babeljs.io/docs/plugins/transform-class-properties/ ,那么您可以只使用static defaultProps = {...}; 。 无需更改构造函数。 否则,您需要在外部分配:

class X extends React.Component {
}
X.defaultProps = {...};

还..

class X extends React.Component {
  props = {
    ...
  }
}

@efernandesng这不是受支持的模式。 它不会表现得像defaultProps并且它会改变您不应该做的this.props

似乎我无法使用父类实例化 defaultProps,以便我可以将这些道具传递给其中的另一个子类。

有没有标准的 es6 方法来做到这一点? 这里的所有方法对我都不起作用。

似乎我无法使用父类实例化 defaultProps,以便我可以将这些道具传递给其中的另一个子类。

我不明白你的意思。 你能举个例子吗?

当然,对此感到抱歉。

这是一个组件:

import React, 
{
  Component,
  PropTypes
}                     from 'react';
import { TimerView }  from './TimerView'

class Timer extends Component {
  constructor(props) {
    super(props);
  }

  componentWillReceiveProps(props) {
    console.log('Will receive props')
  }

  render() {
    console.log("Timer loaded")

    return (
      <TimerView {...props} />
    )
  }
}

Timer.propTypes = {
  status: PropTypes.string.isRequired,
};

Timer.defaultProps = {
  status: "This is the Timer",
};

export default Timer;

当我运行 webpack-dev-server 时,出现此错误:
Uncaught ReferenceError: props is not defined

一定是我做错了什么......

propsrender()方法中的未绑定变量。 它应该是<TimerView {...this.props} />

天啊。
我完全错过了这个。 我想因为我和类一样使用无状态组件,所以我对这个感到困惑。

谢谢你,先生。

没问题@jeanmichelcote! 它发生了:)

访问其他道具来定义 defaultProps 被认为是一种反模式?

class Comp extends from React.Component {
  static propTypes: {
    num: React.PropTypes.number.isRequired,
    action: React.PropTypes.func,
  };

  static defaultProps: {
    action: () => console.log(this.props.num), // "this" is invalid in static context
  };

  render() {
    return (
      <button onClick={this.props.action}>
        {`Log #${this.props.num}`}
      </button>
    );
  }
}

@romulof看起来您正在尝试从静态方法中引用实例变量。 你不能这样做,因为没有办法知道你在谈论哪个this 。 根据定义,静态事物总是存在于实例的上下文之外。

@romulof这在所有面向对象的语言中

static defaultProps: {
    action: function() {
        console.log(this.props.num), // "this" depends on the context where it is run
    }
};

@sbussard :没错。

我的问题是关于defaultProps被实现为静态对象。
也许允许它是一个函数,由构造函数调用。

它有意在类之外,以便优化编译器可以在调用站点将其内联。

那么最终的答案是什么呢?

@gaearon你提到过

它有意在类之外,以便优化编译器可以在调用站点将其内联。

但这是否意味着在使用“类实例字段”和/或“类静态字段”时无法对其进行优化? 我想我正试图了解哪种方法是首选的以及为什么。

那么最终的答案是什么呢?

如果你想坚持使用 ES6,请在底部分配:

class MyComponent extends Component { /* ... */ }
MyComponent.defaultProps = { /* ... */ };

如果您正在使用 Create React App,或者您对实验性语法感到满意并启用了类属性转换,则可以执行以下操作:

class MyComponent extends Component {
  static defaultProps = { /* ... */ };
  /* ... */
}

这些方法是完全等效的。 请注意,如果您还使用装饰器,您可能会在组合这些转换时遇到奇怪的错误。 所以我不建议将装饰器与类属性一起使用。

我希望这有帮助!

但这是否意味着在使用“类实例字段”和/或“类静态字段”时无法对其进行优化? 我想我正试图了解哪种方法是首选的以及为什么。

最后分配和使用类属性没有区别。 类属性为赋值减糖。 请使用 Babel 网站上的 REPL 来检查代码编译成什么。

我对@romulof谈到的同一个问题很好奇。 当然,我可以使用static defaultProps来定义默认属性,但是如果我想使用上下文怎么办?

为什么这很有用?

我有一个通用的模态组件,它有titleonSubmit道具。 有时我想使用具有相同道具但来自我应用程序的完全不同部分的模态。 对于title这工作得很好。

class CreateUserModal extends Modal {
  static defaultProps = { title: 'Create a new user' }
}

然而, onSubmit处理程序恰好是一段不错的代码,它需要上下文,因为它使用从连接 redux 填充的 prop。 目前我没有办法抽象这段代码,因为上下文不能用于设置父类的道具。

我想要做的并不是真正的反模式(或者至少我认为不是)所以我想知道是否有另一种方法可以做到这一点?

我希望我能做类似的事情

class CreateUserModal extends Modal {
  constructor (props) {
    super({
      title: 'Create a new user',
      onSubmit: () => {
        // do a load of stuff using props
      }
    })
  }
}

但它不起作用。

@roberttod您是否找到了解决问题的方法? 谢谢

我想问一个后续问题,
如果我使用 create react app (react-scripts v1.0.12),是否可以将初始状态定义为

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  state = {...};
}

与使用构造函数将初始状态定义为:

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  constructor(props) {
    super(props);

    this.state = {...};
  }
}

具体来说,第一种方法是否有任何性能影响?

这是完全一样的东西,没有区别。

@jhabdas好吧,所以当 defaultProps 定义为:

static defaultProps = {
}

如何从类方法访问它,因为:

this.defaultProps

返回undefined

@majioa我不知道那个类级 API,但一个想法是将默认道具缓存为一个单独的对象并引用它。 你怎么认为?

@majioa

class Foo extends React.Component {
  static defaultProps = { param: 1 };
  render() {
    return Foo.defaultProps.param;
  }
}

我遇到了同样的问题,你应该安装babel-plugin-transform-class-properties

npm install -D babel-plugin-transform-class-properties

然后将"transform-class-properties"到 .babelrc

{
  "presets": ["env", "react"],
  "plugins": ["react-hot-loader/babel", "transform-class-properties"]
}

静态获取 defaultProps() {
返回 {
汽车:“梅赛德斯”
}

@Arm7107这是低效的,因为每次创建元素时它都会创建一个新对象。 我强烈建议不要使用这个。 要么分配一个属性:

MyComponent.defaultProps = {
  // ...
}

或使用实验性静态类属性语法:

class MyComponent extends React.Component {
  static defaultProps = {
    // ...
  };

  // ...
}

(为此你需要一个 Babel 插件)

我将锁定此问题,以防止进一步出现在 Google 结果中的错误建议。

此页面是否有帮助?
0 / 5 - 0 等级