React State and Props

In this lesson we’re going to explore React State and Props, but just before we do, let’s perform a small refactor on our Tweet List component.

We’ve currently got a little duplication in our UI, where we have two hardcoded tweets:

<div className="card mb-2">
    <p className="card-body">
        This is a tweet
    </p>
</div>

Knowing React treats everything as components, it seems logical we could take this “Tweet” markup and turn it into its own component and we can!

Create a new javascript file and call it Tweet.js, then add the standard React component markup we saw earlier…

import React from 'react';

export default class Tweet extends React.Component {
    render() {
        return ()
    }
}

Now cut this html from List.js

<div className="card mb-2">
    <p className="card-body">
        This is a tweet
    </p>
</div>

And go ahead and paste it into the render method in Tweet.js

You should end up with this in Tweet.js:

import React from 'react';

export default class Tweet extends React.Component {
    render() {
        return (
            <div className="card mb-2">
                <p className="card-body">
                    This is a tweet
                </p>
            </div>
        )
    }
}

And finally, back in List.js, we can render our new Tweet component as many times as we like…

import React from 'react';
import Tweet from './Tweet'

export default class List extends React.Component {
    render() {
        return (
            <>
                <h3>Tweets</h3>

                <Tweet />
                <Tweet />
            </>);
    }
}

Nice, we have two tweets.

But I’m guessing we don’t want to keep modifying this markup every time we want to post a new tweet!

Let’s make this a little more dynamic.

What we really want is a way to loop over a collection of tweets and render our Tweet component for each one.

UI state in your components

To this end we can use “state” in our React components.

State takes the form of a javascript object which is private to (and controlled by) a component. This makes it a great place to store any data you want your UI to “react” to.

Want to show a list of people? Add an array of “person” javascript objects to state.

Want to show a list of tweets? Add an array of “tweet” objects instead…

Let’s give it a go; head over to List.js and add this state to the top of the class (just before the render method)…

export default class List extends React.Component {

    state = {
        tweets: [
            "One tweet",
            "Two tweets",
            "Three tweets",
            "Four"
        ]
    }

	// existing render method
    render() {

In this case tweets is an array of strings. It’s worth noting this could just as easily be an array of objects…

state = {
    tweets: [
        { contents: "One tweet" },
        { contents: "Two tweets" },
        { contents: "Three tweets" },
        { contents: "Four" },
    ]
}

But for now, we’ll stick to our list of strings.

Now to render our Tweet component for each item in the Tweets array.

Replace the existing render method in List.js with this one:

render() {
    return (
        <>
        	<h3>Tweets</h3>
        	{ this.state.tweets.map(tweet => <Tweet />) } 
        </>);
}

Here we’re using map, which is a javascript function for looping over items in an array and doing something with them.

In this case we’re using it to loop over our array of tweets (strings) in order to render our Tweet component for each one.

Props for passing data between components

Run this in the browser and you’ll see four identical Tweet cards, but what about the text we want each one to display? (“One tweet”, “Two tweets” etc.)

To show each string from our array we need a way to pass it along to our Tweet component.

Something like this…

render() {
    return (
        <>
        	<h3>Tweets</h3>
        	{this.state.tweets.map(tweet => <Tweet text={tweet}/>) } 
		</>);
}

Here we’ve “forwarded” the array item, aliased as tweet (a string in our case) to our Tweet component via a property called text.

This is very similar to lambdas in C#. If you’ve ever written x=>x. in C#, this is pretty much the same thing, so I could have called tweet => anything I fancied and it would still work.

But our Tweet component still hasn’t the foggiest what to do with this text property! So let’s rectify that…

Head over to Tweet.js and replace the hardcoded “This is a tweet” with {this.props.text}.

render() {
    return (
        <div className="card mb-2">
        	<p className="card-body">
        		{this.props.text}
			</p>
		</div>
	)
}

React gives us access to any properties set on our components, using the props object.

In this case we named our property text and so we can access this in our Tweet component via this.props.text.

Check it out in the browser now and you should see four distinctly different tweets!

Next time we’ll look at populating our tweets list with data from the server (our API).