Transferring Props Back

Sometimes in React, we will wrap a component in an abstraction, which will only expose a simple property to do something that might have more complex implementation details.

Therefore, we can use JSX spread attributes to pass props from an owner component to the ownee one:

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

Ignoring JSX, you can also use any object helpers such as ES6 Object.assign or Underscore _.extend:

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

Manual Transfer

Most of the time you should explicitly pass the properties down. This ensures that you only expose a subset of the inner API.

function FancyCheckBox(props) {
    var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';

    return (
        <div className={fancyClass} onClick={props.onClick}>
            {props.children}
        </div>
    );
}

ReactDOM.render(
    <FancyCheckBox checked={true} onClick={console.log.bind(console)}>
    </FancyCheckBox>,
    document.getElementById('content')
);

But what about the name, title or onMouseOver prop?

Transferring with ... in JSX

Sometimes, it's fragile(易碎) and tedious(冗長) to pass every property along. Therefore, we can use destructuring assignment to extract.

As followed, you can list out all the properties that you would like to consume(銷毀), followed by ...other.

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

That ensures that you pass down all the props EXCEPT the consumed prop checked:

function FancyCheckBox(props) {
    var { checked, ...other} = props;
    var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';

    /** other contains { onClick: console.log } but not the checked property */

    return (
        <div {...other} className={fancyClass} />
    );
}

ReactDOM.render(
    <FancyCheckBox checked={true} onClick={console.log.bind(console)} >
    </FancyCheckBox>,
    document.getElementById('content');
);

Consuming and Transferring Again

If you want to consume a property but also want to pass it along, you can repass it explicitly. Rather than passing the full props, this way is easier to refactor and lint(語法檢查).

function FancyCheckbox(props) {
    var { checked, title, ...other } = props;
    var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
    var fancyTitle = checked ? 'X ' + title : 'O ' + title;

    return (
        <label>
            <input {...other} checked={checked} className={fancyClass} type="checkbox" />
            {fancyTitle}
        </label>
    );
}

NOTE:

Order matters. By putting the {...other} before your JSX props you ensure that the consumer of your component can't override them.

Rest and Spread Properties ...

Rest properties allow you to extract the remaining properties from an object into a new object. It excludes every other property listed in the destructuring pattern.

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

console.log(x);     /** => 1              */
console.log(y);     /** => 2              */
console.log(z);     /** => { a: 1, b: 2 } */

NOTE:

To transform rest and spread properties using Babel 6, you need to install the es2015 preset, the transform-object-rest-spread plugin and configure them in the .babelrc file.

Transferring with Underscore

If you don't use JSX, you can use a library to achieve the same pattern. Underscore supports _.omit to filter out properties and _.extend to copy properties onto a new object.

function FancyCheckBox(props) {
    var checked = props.checked;
    var other = _.omit(props, 'checked');
    var fancyClass = checked ? 'fancyChecked' : 'fancyUnchecked';

    return (
        React.DOM.div(_.extend({}, other, { className: fancyClass }))
    );
}

results matching ""

    No results matching ""