First, let's create a couple of components that expect different types of property values:
import React, { Component } from 'react';
export default class MyButton extends Component {
// Renders a "<button>" element using values
// from "this.props".
render() {
const { disabled, text } = this.props;
return <button disabled={disabled}>{text}</button>;
}
}
This simple button component expects a boolean disabled property and a string text property. Let's create one more component that expects an array property value:
import React, { Component } from 'react';
export default class MyList extends Component {
render() {
// The "items" property is an array.
const { items } = this.props;
// Maps each item in the array to a list item.
return <ul>{items.map(i => <li key={i}>{i}</li>)}</ul>;
}
}
You can pass just about anything you want as a property value via JSX, just as long as it's a valid JavaScript expression. Now let's write some code to set these property values:
import React from 'react';
import { render as renderJSX } from 'react-dom';
// The two components we're to pass props to
// when they're rendered.
import MyButton from './MyButton';
import MyList from './MyList';
// This is the "application state". This data changes
// over time, and we can pass the application data to
// components as properties.
const appState = {
text: 'My Button',
disabled: true,
items: ['First', 'Second', 'Third']
};
// Defines our own "render()" function. The "renderJSX()"
// function is from "react-dom" and does the actual
// rendering. The reason we're creating our own "render()"
// function is that it contains the JSX that we want to
// render, and so we can call it whenever there's new
// application data.
function render(props) {
renderJSX(
<main>
{/* The "MyButton" component relies on the "text"
and the "disabed" property. The "text" property
is a string while the "disabled" property is a
boolean. */}
<MyButton text={props.text} disabled={props.disabled} />
{/* The "MyList" component relies on the "items"
property, which is an array. Any valid
JavaScript data can be passed as a property. */}
<MyList items={props.items} />
</main>,
document.getElementById('root')
);
}
// Performs the initial rendering...
render(appState);
// After 1 second, changes some application data, then
// calls "render()" to re-render the entire structure.
setTimeout(() => {
appState.disabled = false;
appState.items.push('Fourth');
render(appState);
}, 1000);
The render() function looks like it's creating new React component instances every time it's called. React is smart enough to figure out that these components already exist, and that it only needs to figure out what the difference in output will be with the new property values.
Another takeaway from this example is that you have an appState object that holds onto the state of the application. Pieces of this state are then passed into components as properties, when the components are rendered. State has to live somewhere, and in this case, it's outside of the component. I'll build on this topic in the next section, when you will learn how to implement stateless functional components.