Update State with usestate in an Array of Objects - part 11

←React child to parent communication

React tutorial - state array of objects and rendering react lists and keys


We already know how to update a function using state; now I'd like to update my lists when I fill out and submit a form, and I'd like to output data dynamically on the screen. 

In our application, we provide the number of lists manually, whereas, in a dynamic application, there is no indication of what number of lists we will receive in advance. Now we'll be working in that room.

Multiple Components Map

We saved an array of objects in App.js that stores the name, language, and level values of users, as shown below, and it renders in Lists.js, where we have multiple components.

import List from './component/Lists
const App = () => {
  const course = [
    {
    	id: 1,
        name: 'Sandmus',
        language: 'JavaScript',
        level: 'Beginner'
    },
    {
    	id: 2,
        name: 'Simba',
        language: 'HTML/CSS',
        level: 'Medium'
    },
    {
    	id: 3
        name: 'Jenny',
        language: 'JavaScript',
        level: 'Advance'
    }
 ]
 
 return (
 	<Lists detail={course} />
   )
}
export default App

An array of objects
import List from './List'
const Lists = ({detail}) =>
  return (
    <section>
      <List name={detail[0].name} language={detail[0].language} level={detail[0].level} />
      <List name={detail[1].name} language={detail[1].language} level={detail[1].level} />
      <List name={detail[2].name} language={detail[2].language} level={detail[2].level} />
    </section>
  )
}
export default Lists
Rendering Multiple Components

import FancyBorder from './FancyBorder';
import './List.css'
const List = ({name, language, level}) => {
    return (
        <FancyBorder className="list">
            <h3>{name}</h3>
            <span>{language} : {level}</span>
        </FancyBorder>
    )
}
export default List
Output User data


The goal of this section is to transform arrays into lists of elements using the JavaScript map() function.

map() method is a built-in JavaScript method, that allows you to iterate over a given array and return a new array. Method map() accepts a function as an argument, which is then used to execute the function for each item on which it is called. The output of this function is the element that will be added to the newly generated array.

Let us apply this theory to our demo application.

Curly braces are used to surround any JavaScript expressions used in JSX, and they are where we are going to use the JavaScript map() method, which is used to iterate through the detail array.  Array, detail.map() will iterate through each user, so specify the arrow function, pass the user as an argument, and return JSX element List for each user.

{detail.map((user) => <List />)}

we convert an array into a list of elements here, and now put the attributes or props on the List component like we did before, then extract name, language, and level.

import List from './List'
const Lists = ({detail}) => {
  return (
    <section>
      {detail.map((user) =>
        <List>
          name={user.name} 
          language={user.language} 
          level={user.level}
        />
      )}
    </section>
  )
}
export default Lists

This is how we get rid of the hard-coded List element from JSX; if you open a browser, you will see that our list is rendered dynamically just as before.

In the previous chapter, we learned how to pass data from a child component to a parent component and added an addDetailHandler function inside App.js. When we fill out the form and submit it, the addDetailHandler function is triggered and the submitted value is alerted.

Update state array of objects - Rendering Lists

We'll now move on to the section of the project where we'll update the list of arrays and add new users to the list. React's state management is what we use when we want to modify or update something.

At the start of the App component, we'll import the useState hook. We'll then extract the course array outside of the App function.

import { useState } from 'react'
const course = [
  {  
      name: 'Sandmus',
      language: 'JavaScript',
      level: 'Beginner'
  },
  { 
      name: 'Simba',
      language: 'HTML/CSS',
      level: 'Medium'
  },
  { 
      name: 'Jenny',
      language: 'JavaScript',
      level: 'Advance'
  }
]

const App = () => {}

Now add the array destructuring pattern to the App function using const, and add the first variable users to hold the current state. add the state updating function setUsers to update the list of arrays already present, declare useState hook, and then pass the initial state value course.

const App = () => {
  const [users, setUsers] = useState(course)
}

We now wish to update the list, an array that is stored in state. Because you can't mutate the existing state in React, you can't add new items to it and have them render. What you must do is create a new array and set it as the new state value.

Inside the App component, we have a function with the parameter addDetailHandler(newUserDetail), and the parameter contains the submitted value. To update an array, we'll make a copy of an existing array using the spread operator [...arr] and then set the state to use that copy.

const addDetailHandler = (newUserDetail) => {
  setUsers([newUserDetail, ...users])
  
}

This will cause React to re-render the component, and the render will reflect the most recent state change.  The useState renders only If the parameter it receives is different from an earlier one.

Pass the users variable as a value to the props detail on the Lists element in JSX.

const App () => {
  const [users, setUsers] = useState(course)
  
  const addDetailHandler = (newUserDetail) => {
  setUsers([newUserDetail, ...users])
 }
 return (
   <Lists detail={users} />
 )
}

React keys

If you work with a list, you will notice that the data outputs correctly, but there is a warning regarding unique keys in the dev tools. What are keys, exactly, and why is there a warning on the console about a missing key?

Keys serve as the item's sole identifier in the dynamically generated list. It helps to distinguish specifically which element has changed or been updated, and React only updates the content within rather than re-rendering the entire table.

We are receiving errors in the console because we are displaying the list without using the key.

Every element in the array should have a distinct key for efficiency reasons. Let's update the initial list with a special string id.

const course = [
  {  
      id: 'u1',
      name: 'Sandmus',
      language: 'JavaScript',
      level: 'Beginner'
  },
  { 
      id: 'u2',
      name: 'Simba',
      language: 'HTML/CSS',
      level: 'Medium'
  },
  { 
      id: 'u3',
      name: 'Jenny',
      language: 'JavaScript',
      level: 'Advance'
  }
]

Next, When you submit a new value, let the submitFormHandler function in the UserForm component update the Id in the userDetail object with a random string. I already explain this in the React form submission section.

UserForm.js
...
const submitFormHandler = (e) => {
  e.preventDefault()
  const userDetail = {
      name: name,
      language: language,
      level: level,
      id: 'u' + Math.random().toString()
    }
    
    onAddDetail(userDetail)
    
    setName('')
    setLanguage('')
    setLevel('Beginner')
   }
   return (
   	<form onSubmit={submitFormHandler}>...</form>
   )
}

We should use the key attribute on the List element in the array when extracting the List component.

import List from './List'
const Lists = ({detail}) => {
  return (
    <section>
      {detail.map((user) => 
        <List key={user.id}
          name={user.name} 
          language={user.language} 
          level={user.level}
        />
      )}
    </section>
  )
}
export default Lists

Now that the error has been removed from the console, it is clear that whenever we use map() to convert data into a list of items each element must have a unique identity. 

Conclusion

In this React tutorial series, we are adding new users to the list using state hooks and list re-render when new data is submitted. 

Use the non-mutating method map() to convert data into an array of elements and build a new array from the original array. Use the array spread syntax to create a copy of an existing array, then set the state of the newly created array.

Give each element a distinct identifier and a key attribute to aid React in differentiating between them.

0 Comments:

Post a Comment