React Guide to Props - Part I

React Guide to Props - Part I

Disclaimer: This was intended to be part III of React JSX series, but as for props there's a lot to be covered, we have decided to divide it into a subseries!

In some of our previous articles, you had the opportunity to read about JSX specific stuff, like how to render content in loops and how to do conditional rendering in React.

Today, you will learn how props function. However, before we move to actual prop usage examples, you must first understand the difference between state, props and refs. Once you know what is what, everything will be a lot easier. Here's a short explanation:

The state is similar to attributes in object-oriented programming : it's something local to a class (component), used to better describe it. We'll cover React state management and what should be kept in the local state in another article.

Props are like parameters - they are passed to a component from the caller of a component (the parent) : as if you called a function with certain parameters.

Refs are, as the name suggests, references to nested components (children), used for functionality like triggering of focus or an animation. However, they shouldn't be used too much, as the most proper way to communicate between the components is via props.

Now that we have covered all the basic differences, we can start with the prop passing!

All of the below applies to React Native as well!

Passing props - the standard way

Passing props is pretty straightforward: you send a prop by specifying the name under which will it be available in child component and defining what the prop should equal:

render() {
    return (
        <Child
            propName={propValue}
        />
    )
}

Here is a bit more realistic example:

render() {
    // strings don't have to be wrapped with {},
    // but it's better to get used to wrapping everything
    return (
        <Movie
            actors={[
                ...
            ]}
            details={{
                director: "Director name",
                ...
            }}
            duration={120}
            released={true}
            title={"Movie title"}
        />
    )
}

That's basically it for sending a prop! Below you'll find some more specific props you'll definitely be using at some point when coding in React!

Boolean props

If you want to pass a true value as a prop, you can do it next way:

render() {
    // No need for "released={true}"!
    return (
        <Movie
            released
        />
    )
}

In the same manner, if you want to pass a false value, you can do it by just not passing anything at all:

render() {
    // This will work the same way as if you passed "released={false}"!
    return (
        <Movie />
    )
}

If the boolean value is contained within a variable, then, of course, you'll have to pass it.

render() {
    let booleanVariable = true; // this will often be calculated
    return (
        <Movie
            released={booleanVariable}
        />
    )
}

You can directly calculate the value of a prop when passing it, as well:

render() {
    return (
        <Movie
            released={value1===value2}
        />
    )
}

Just keep in mind that it should be clear what's happening in the code, if the expression is too long, move it above the return statement or even to a separate function:

isFormValid() {
    // various checks, whether every form field is of correct format
}
render() {
    return (
        <Form
            disabled={!this.isFormValid()}
            fields={this.state.fields}
        />
    )
}

Function props

Often, you'll have to pass functions and event handlers as props. The functions you pass need to be bound to the component context. However, don't bind functions in render methods:

handleChange(event) {
    // do something here
}

render() {
    return (
        <div>
            {
                // don't do this!
            }
            <input
                onChange={this.handleChange.bind(this)}
            />
        </div>
    )
}

If you bind a function in the render, everytime a component is rerendered, the new function will be created. Instead, it's the best to use arrow syntax when defining a function (You'll need babel configured to use ES6 syntax!):

handleChange = (event) => {
    // do something here
}

render() {
    return (
        <div>
            <input
                onChange={this.handleChange}
            />
        </div>
    )
}

You might be thinking: that's fine when there are no other parameters to be passed, but what if I need to pass an attribute? Here's how to do it with arrow functions:

handleChange = (parameter1, parameter2) => (event) => {
    // do something here
}

render() {
    return (
        <div>
            <input
                onChange={this.handleChange(parameter1, parameter2)}
            />
        </div>
    )
}

Sending props to this.props.children

Sending the props to child component called directly in code is pretty straight forward, but how do we send the props to children passed as a prop?
This is the way to do it:

render() {
    let updatedChildren = React.Children.map(this.props.children,
        (child) => {
            return React.cloneElement(child, { newProp: newProp });
        });

    return (
        <div>
            { updatedChildren }
        </div>
    );
}

If your component is having just one child, there's no need for mapping, you can do this as well:

render() {
    return (
        <div>
            {
                React.cloneElement(this.props.children, {
                    newProp: newProp
                })
            }
        </div>
    );
}

Props and the '...'

You might have seen the three dots earlier and wondered what they mean. Code similar to one in next example is quite common in React world:

render() {
    return (
        <Movie
            {...this.props}
        >
    );
}

The ... is a spread operator, and it'll send each of the key-value pairs inside of this.props as a separate prop to Movie component. Let's say that we have an object movie:

const movie = {
    title: "Inception",
    releaseDate: "16.07.2010",
    genre: [
        "Action", "Adventure", "Sci-Fi",
    ],
};

We should pass all of the key-value pairs from movie object to Movie component. Here's how we'd do it without the ...:

render() {
    return (
        <Movie
            title={movie.title}
            releaseDate={movie.releaseDate}
            genre={movie.genre}
        />
    );
}

Now, the code above can be much shorter using the three dots syntax, and work completely the same:

render() {
    return (
        <Movie {...movie} />
    );
}

However, although it's way shorter, it can get a bit messy over time, so don't overuse it! Also, keep in mind, that although the ... works as spread operator for arrays as well, when sending props you should only use it on objects!

Thank you for your time reading this article!

Now that we've gone through the prop basics, you can make your components communicate and understand better how they do so!

This, however, is just a beginning, as there's a lot more to learn about component communication.

We'll be covering the communication from children to parent and between two same level components in our next article. Subscribe and we'll notify you when it comes out!