Create your first React app - Part 2 (A component that lists all users)

In this part of the project we'll create a component that shows a list of all the 'user' objects. We'll also discuss props, which are an essential concept in React.

In index.js, replace // TODO: put the UserList component here later with this code:

// The UserList component
function UserList({users, onUserSelected}){
    
    return (
        <div className="user-list">
            <h2>User List</h2>
            <ul>
                {users.map(u => (
                    <li key={u.id} onClick={()=>{onUserSelected(u.id)}}>{u.firstName + ' ' + u.lastName}</li>
                ))}
            </ul>
        </div>
    );

}

Here are some things to note about this component function:

  1. It declares an object as a parameter. The object that you pass into a component function declares the props
    • The first prop declared is 'users', and soon you'll see that the 'users' state/array from the RootComponent will be passed in for this.
    • The second prop is 'onUserSelected', this is a function that is used in the click event handler for each LI element in the list (more on that soon too). Props that are for event handler functions are commonly prefixed with 'on'. that must be passed into a component (we'll talk more about them soon)
  2. The JSX code that the component returns a DIV that has a className property. To add CSS classes to elements in JSX, you must use 'className' instead of 'class'.
  3. Inside the UL element is embedded JavaScript that uses the map() method on the 'users' prop/array to generate an LI element for each user.
    1. When you use map() to generate a JSX LI element, each element must have a unique key (we are using the user's id property).
    2. As mentioned, the click handler for each LI is calling the 'onUserSelected' prop, which is a function that will get passed in from the root component. This will allow the root component to handle the event. You'll see how this gets passed in as a prop in a minute.
    3. Inside of each LI element, we are embedding JavaScript code that displays the user's first and last name.

That's a lot to digest for React beginners! But we'll practice writing code like this a lot throughout the course.

In React, you can send data from a parent component to a child component by passing it as a prop. Now, we'll add code to the root component that declares the UserList component as a child, and passes the users array in as a prop.

Update the RootComponent() function to look like this:

function RootComponent(){

    console.log("rendering root component......");
    
    const [users, setUsers] = useState([]);

    useEffect(() => {
        setUsers(uda.getAllUsers());
    }, [])

    const handleAddUser = (evt) => {
        console.log("TODO: add a new user")
    }

    const handleUserSelected = (userId) => {
        console.log("ID of user selected:", userId);
    }
        
    return (
        <div>
            <h1>User Manager</h1>
            <button onClick={handleAddUser}>Add User</button>
            <p>Number of users: {users.length}</p>
            <UserList users={users} onUserSelected={handleUserSelected} />
        </div>
    );

}

There are 3 things to note about the changes to the root component:

  1. We added the UserList component to the JSX that gets returned
    1. To add a child component to a component, you declare it in the JSX as if it were an HTML element (but these elements must start with a capital letter to distinguish them from standard HTML elments)
  2. We passed the users state into the UserList for the 'users' prop
  3. We declared the handleUserSelected() function and passed it into the UserList as the 'onUserSelected' prop. Remember that this function will get called when an LI is clicked on.

Run the app, and you should see a list of users appear. And, if you click on a users's name, you should see a message appear in the console log.

This code demonstrates two very important concepts in React:

This is how components communicate and send data in React.

In part 1 you learned that you should never directly modify state, instead you should use the 'set' method that you get when you declare state. You should never modify props in your code either. Instead, a child should allow the parent to manage the state of a prop. As we progress with this project, you'll see that the root component will send functions as props to child components. The children will trigger these functions, which allows the parent to make changes to the 'users' state by calling setUsers().