• 传递 Props
    • 手动传递
    • 在 JSX 里使用 ... 传递
    • 使用和传递同一个 Prop
    • 剩余属性和展开属性 ...
    • 使用 Underscore 来传递

    传递 Props

    React 里有一个非常常用的模式就是对组件做一层抽象。组件对外公开一个简单的属性(Props)来实现功能,但内部细节可能有非常复杂的实现。

    可以使用 JSX 展开属性 来合并现有的 props 和其它值:

    1. <Component {...this.props} more="values" />

    如果不使用 JSX,可以使用一些对象辅助方法如 ES6 的 Object.assign 或 Underscore _.extend

    1. React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));

    下面的教程介绍一些最佳实践。使用了 JSX 和 试验性的ECMAScript 语法。

    手动传递

    大部分情况下你应该显式地向下传递 props。这样可以确保只公开你认为是安全的内部 API 的子集。

    1. function FancyCheckbox(props) {
    2. var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
    3. return (
    4. <div className={fancyClass} onClick={props.onClick}>
    5. {props.children}
    6. </div>
    7. );
    8. }
    9. ReactDOM.render(
    10. <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
    11. Hello world!
    12. </FancyCheckbox>,
    13. document.getElementById('example')
    14. );

    name 这个属性怎么办?还有 titleonMouseOver 这些 props?

    在 JSX 里使用 ... 传递

    注意:

    在下面的例子中,--harmony 标志是必须的因为这个语法是ES7的实验性语法。如果用浏览器中的JSX转换器,以 <script type="text/jsx;harmony=true">简单的打开你脚本就行了。详见Rest and Spread Properties …

    有时把所有属性都传下去是不安全或啰嗦的。这时可以使用 解构赋值 中的剩余属性特性来把未知属性批量提取出来。

    列出所有要当前使用的属性,后面跟着 ...other

    1. var { checked, ...other } = props;

    这样能确保把所有 props 传下去,除了 那些已经被使用了的。

    1. function FancyCheckbox(props) {
    2. var { checked, ...other } = props;
    3. var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
    4. // `other` 包含 { onClick: console.log } 但 checked 属性除外
    5. return (
    6. <div {...other} className={fancyClass} />
    7. );
    8. }
    9. ReactDOM.render(
    10. <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
    11. Hello world!
    12. </FancyCheckbox>,
    13. document.getElementById('example')
    14. );

    注意:

    上面例子中,checked 属性也是一个有效的 DOM 属性。如果你没有使用解构赋值,那么可能无意中把它传下去。

    在传递这些未知的 other 属性时,要经常使用解构赋值模式。

    1. function FancyCheckbox(props) {
    2. var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
    3. // 反模式:`checked` 会被传到里面的组件里
    4. return (
    5. <div {...props} className={fancyClass} />
    6. );
    7. }

    使用和传递同一个 Prop

    如果组件需要使用一个属性又要往下传递,可以直接使用 checked={checked} 再传一次。这样做比传整个 this.props 对象要好,因为更利于重构和语法检查。

    1. function FancyCheckbox(props) {
    2. var { checked, title, ...other } = props;
    3. var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
    4. var fancyTitle = checked ? 'X ' + title : 'O ' + title;
    5. return (
    6. <label>
    7. <input {...other}
    8. checked={checked}
    9. className={fancyClass}
    10. type="checkbox"
    11. />
    12. {fancyTitle}
    13. </label>
    14. );
    15. }

    注意:

    顺序很重要,把 {...other} 放到 JSX props 前面会使它不被覆盖。上面例子中我们可以保证 input 的 type 是 "checkbox"

    剩余属性和展开属性 ...

    剩余属性可以把对象剩下的属性提取到一个新的对象。会把所有在解构赋值中列出的属性剔除。

    这是 ECMAScript 草案 中的试验特性。

    1. var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    2. x; // 1
    3. y; // 2
    4. z; // { a: 3, b: 4 }

    注意:

    要用 Babel 6转换 rest 和 spread 属性,你需要安装 es2015 preset,transform-object-rest-spread 插件并在 .babelrc 里配置他们.

    使用 Underscore 来传递

    如果不使用 JSX,可以使用一些库来实现相同效果。Underscore 提供 _.omit 来过滤属性,_.extend 复制属性到新的对象。

    1. function FancyCheckbox(props) {
    2. var checked = props.checked;
    3. var other = _.omit(props, 'checked');
    4. var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
    5. return (
    6. React.DOM.div(_.extend({}, other, { className: fancyClass }))
    7. );
    8. }