React, State, and You
Tags: react, javascript
Published: 2020-10-21 14:04:55

---
title: React, State, and You
published: true
description: How to come to terms with the structure of components, state and props
tags: React, Javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/gughxsem62v3fwt3wfxu.png
---

React can be daunting to start off with, but once you learn some basic concepts even the most complicated of interactions can be simple. The thing to remember is you can only really influence three basic things

1. Children
2. Props
3. State

So let's learn them.

## Children

All React apps start from a single component, which is sometimes called the 'entry point' for your application:

```js
ReactDOM.render(<App />, rootElement);
```

Here, `<App />` is our 'entry point'. It's the component from which any other component in our application needs to be a child of. We can then define `<App />` to be something like this:

```js
export default function App() {
  return (
    <Child>
      <GrandChild />
    </Child>
  );
}
```

The structure is `<App> -> <Child> -> <GrandChild>` with each being a 'child' of it's parent.

## Props

The second fundamental concept is the properties that you provide to your components. Properties, are variables that the parent wants to share with a child. The child can then make use of these properties - shortened to `props`. Properties are defined to a child, and subsequently consumed by a child as follows:

```js
const Child = (props) => (
  <p>Hi, my name is {props.name} </p>
);

export default function App() {
  return (
    <div>
      <Child name="Billy" />
      <Child name="Mary" />
      <Child name="Colin" />
    </div>
  );
}
```

Here, each child is provided a different value for 'name' and the `Child` component itself uses the name provided in the `props` object. When using functional components like this, `props` is always the first argument to your function, if you were using `class Child extends React.Component` you would need to use `this.props` but otherwise it works the same. Props can contain anything you want, the only preset prop is `children` which are 'children' provided by the parent, for example:

```js
const Child = (props) => (
  <div>
    <p>Hey I am a child</p>
    {props.children && <div>And I have my own children {props.children}</div>}
  </div>
);

const GrandChild = () => <p>Hey I am a grandchild!</p>;

export default function App() {
  return (
    <Child>
      <GrandChild />
    </Child>
  );
}
```

A `<GrandChild>` is being provided to the `<Child>` by the `<App>`. This will be accessible to the `<Child>` using `props.children`. You can see in the `Child` function that we are checking if `props.children` is set and if it is we are rendering them in the `<div>` component.

## State

So we have seen what a `parent` can provide to a `child` through `props`, but what if the child itself wants to maintain some data of it's own. This is where 'state' comes in, and effectively state is a variable that lives inside of a component and exists during the lifetime of that component. There are some differences between 'functional' and 'class' based components, here I will be talking exclusively about the 'functional' format for state management. Let's look at a really simple example:

```js
const names = ['Mary', 'Bill', 'Fred', 'Juan']

export default function App() {
  return (
    <div>
      <h1>Today is who's birthday?</h1>
      <ul>
        {names.map((name) => <li>{name}</li>)}
      </ul>
    </div>
  );
}
```

Here we have a simple array of names, which our component is then rendering into a list. We want to maintain 'state' of who's birthday it actually is. One really simple way would be to include a variable as follows:


```js
const names = ["Mary", "Bill", "Fred", "Juan"];

export default function App() {
  const birthdayPerson = "Bill";
  return (
    <div>
      <h1>Today is who's birthday?</h1>
      <ul>
        {names.map((name) => (
          <li>{`${name}${
            name === birthdayPerson ? " HAPPY BIRTHDAY!!!" : ""
          }`}</li>
        ))}
      </ul>
    </div>
  );
}
```

We can change the `birthdayPerson` to equal anyone from the list, but currently it's hardcoded. What if we want the user to be able to click one of the names in the list, thereby setting the `birthdayPerson` to that person. Sadly we can't just create our own variable and update it because React works by re-rendering changes when it detects a change - so it needs help detecting those changes. So the following **won't work**:

```js
const names = ["Mary", "Bill", "Fred", "Juan"];

export default function App() {
  let birthdayPerson = "Bill";
  return (
    <div>
      <h1>Today is who's birthday?</h1>
      <ul>
        {names.map((name) => (
          // this won't work!
          <li onClick={() => (birthdayPerson = name)}>{`${name}${
            name === birthdayPerson ? " HAPPY BIRTHDAY!!!" : ""
          }`}</li>
        ))}
      </ul>
    </div>
  );
}
```

Instead, we need to use the `useState` hook. `useState` is a 'hook' function built into React that allows us to declare a variable and get a function that allows us to change this variable. This way React knows when the variable has changed so can compute the new render and decide what needs to update efficiently.

```js
import React, {useState} from 'react';
const names = ["Mary", "Bill", "Fred", "Juan"];

export default function App() {
  const [birthdayPerson, setBirthdayPerson] = useState("Fred");
  return (
    <div>
      <h1>Today is who's birthday?</h1>
      <ul>
        {names.map((name) => (
          <li onClick={() => setBirthdayPerson(name)}>{`${name}${
            name === birthdayPerson ? " HAPPY BIRTHDAY!!!" : ""
          }`}</li>
        ))}
      </ul>
    </div>
  );
}
```

_Always remember to import `useState` when you want to use it._ `useState` is a function that will provide your component with an array. The first thing in the array is the current value for the state, with the argument passed into `useState(arg)` being the `initial` state (in the above case `birthdayPerson === "Fred"`). The second thing in the array is the function to call that will update the value, and will take care of Reacts re-rendering for you. In the above example the `onClick` of each list item is using it to `setBirthdayPerson(name)` where `name` is the name for that particular item in the names array.

## Bringing it all together.

So now you have `children` and then parents are providing `props` to it. Each component can now also have their own `state` for managing things, but now we want to tie these things together. Well there isn't much else to cover, just that `state` and the functions to update it can be fed into `props`... and this is really where the basic building blocks open into a lot of possibilities.

### The Spec

We want to make an address book, names on the left that we can selected, and on the right we see more information for the selected name. We will have a data source for our address book which is just an array of objects like this:

```js
{
  _id: "5f90374ad2e52f3fbe46d149",
  name: {
    first: "Bentley",
    last: "Rosales"
  },
  company: "ACUSAGE",
  phone: "+1 (961) 423-2258",
  address: "930 Eckford Street, Elfrida, Vermont, 1570",
  photoUrl:
      "https://avatars.dicebear.com/api/avataaars/5f90374ad2e52f3fbe46d149.svg"
}
```

We want the list to show just a first name, but on selected we want to see their address, phone number, company, and of course their picture!

### Component Structure

So like everything we have a single point of entry, this will be our `<App>`. Our `<App>` will then have two child components `<List>` - which shows our selectable list of people, and `<View>` - which shows the currently selected person.

### <View>

This is one of the simplest components so it makes sense to build this one first. All it needs is the right structure to render what the information we want, and a single `prop` `selectedPerson`.

```js
const View = (props) => {
  const { selectedPerson } = props;
  return (
    <div className="view">
      {selectedPerson ? (
        <Fragment>
          <div className="view-heading">
            <img src={selectedPerson.photoUrl} />
            <h2>
              {selectedPerson.name.first} {selectedPerson.name.last}
            </h2>
          </div>
          <p>
            <b>{selectedPerson.company}</b>
          </p>
          <p>{selectedPerson.address}</p>
        </Fragment>
      ) : (
        <p>No one selected</p>
      )}
    </div>
  );
};
```

This is working just using `props` and a single `selectedPerson` prop is expected. If this isn't set we show `<p>No one selected</p>` otherwise we show the data of the person.

### <List>

Next up is the list component, this has to take a few different sources of information from `props`. First it needs the `people` which is the array of names to display. Second, it needs to know if there is a `selectedPerson` so that it can show that that person is selected in the list. Finally it needs to know how to update or `setSelectedPerson` so when a name is clicked it can set the selected person to whoever was clicked. All of this will be provided as props:

```js
const List = (props) => {
  const { people, selectedPerson, setSelectedPerson } = props;
  return (
    <div className="list">
      {people.map((person) => (
        <div
          onClick={() => setSelectedPerson(person)}
          className={
            person === selectedPerson ? "list-item selected" : "list-item"
          }
          key={`person_${person._id}`}
        >
          {person.name.first}
        </div>
      ))}
    </div>
  );
};
```

So you can see we have a list of `people` which we then map and turn into `<div>` elements with the persons first name rendered. We also check if the `person` that we are iterating over is equal to `selectedPerson` and if so we set a different CSS `className`. The `<div>` also gets given an `onClick` function which will invoke the `setSelectedPerson` prop with the respective person.

### <App>

So now we have to tie the two things together, and really the only place to do this is in the parent `<App>` component. This can feed the `people`, `selectedPerson` and `setSelectedPerson` properties to the `<List>` and can provide the `<View>` with the `selectedPerson` property.

```js
import peopleData from "./data";
export default function App() {
  const [selectedPerson, setSelectedPerson] = useState();
  return (
    <div className="address_book">
      <List
        selectedPerson={selectedPerson}
        setSelectedPerson={setSelectedPerson}
        people={peopleData}
      />
      <View selectedPerson={selectedPerson} />
    </div>
  );
}
```

The only things we need here are to import the `peopleData` from our file that has the array of people for the address book, and to create a state variable that holds the `selectedPerson`. We don't provide an initial value for `selectedPerson` in the `useState()` call - because we have ensured that the `<View>` can deal with this being empty.

You can find all of this in a neat sandbox below. Enjoy!

{% codesandbox address-books-royletron-cz2xb %}