bradxr
12/31/2018 - 1:54 PM

09 - Outputting Lists

add general notes

Outputting Lists

  • general notes
  • general notes two

Code Example - Outputting Lists Basics

  • Lists can be outputted with the map method
  • Ensure each list item has a key value, otherwise a console error will be produced
  • These keys can be hardcoded since the data isn't production
  • Key values application:
    • Add 'id' field in each person object in the state
    • Add key prop on Person component
import React, {Component} from 'react';

class App extends Component {
  state = { persons: [ { id: 're3g543fdf' ... }, { id: 'rg98ds453sd' ... } ], }
  
  render() {
  let persons = null;
  
  if (this.state.showPersons) {
    persons = (
      <div>
      // REFERENCE TO ARRAY OF OBJECTS IN STATE.. NEED TO CONVERT TO VALID JSX USING MAP
      { this.state.persons.map( person => {
        return <Person name={person.name} age={person.age} key={person.id} />
      })}
      </div>
    );
  }
  
    return(
      <div>
        {persons}
      </div>
    )
  }
}
export default App;

Code Example - Lists and State

  • To demonstrate how to work with state when using lists we will implement an event handler i.e. deletePersonHandler
  • Within this event handler we should create a copy of the state, this can be done using the slice method or the spread operator
  • Slice method: const persons = this.state.persons.slice();
  • Spread operator: const persons = [...this.state.persons];
  • Do not simply use const persons = this.state.persons; as objects and arrays are reference types meaning that we will actually get a pointer to the original state and mutate the state directly which is NOT recommended
import React, {Component} from 'react';

class App extends Component {
  state = { persons: [ { ... }, { ... } ], }
  
  // EVENT HANDLER TO MANAGE DELETION OF PERSON COMPONENT
  deletePersonHandler = (personIndex) => {
    const persons = [...this.state.persons];
    persons.splice(personIndex, 1);
    this.setState({persons: persons})
  }

  render() {
  let persons = null;
  
  if (this.state.showPersons) {
    persons = (
      <div>
      // PASS INDEX ARGUMENT TO MAP METHOD
      {this.state.persons.map((person, index) => {
        return (
          <Person name={person.name} 
                  age={person.age}
                  key={person.id}
                  click={() => this.deletePersonHandler(index)} />
        )
      })}
      </div>
    );
  }
  
    return(
      <div>
        {persons}
      </div>
    )
  }
}
export default App;

Code Example - Flexible Lists

  • Fixes the issue from '06 - Working with Events & Methods' where we could only update the name for one person
  • Application
    • add id parameter to nameChangedHandler
    • pass person.id to nameChangedHandler within the changed prop, which is later used to identify the correct component
    • make sure that the person exists within the state with the findIndex method, this will return the index of the person
    • grab the person object by index
    • assign person name to user input value based on event.target.value
    • update state immutably
    • set state

Primary Component

import React, {Component} from 'react';
 
class App extends Component {
  state = { persons: [ { ... }, { ... } ] }
  
  // ADDED ID PARAMETER
  nameChangedHandler = (event, id) => {
   
    // IF PERSON CAN BE FOUND IN THE STATE, WILL RETURN THE INDEX
    const personIndex = this.state.persons.findIndex(p => {
      return p.id === id;
    });
    
    // GRAB PERSON OBJECT BY INDEX
    const person = {
      ...this.state.persons[personIndex];
    }
    
    // ASSIGN PERSON NAME TO USER INPUT
    person.name = event.target.value;
    
    // UPDATING STATE IMMUTABLY
    const persons = [...this.state.persons];
    persons[personsIndex] = person;
    
    this.setState({ persons: persons })
  }
  
  render() {
  let persons = null;
  
  if (this.state.showPersons) {
    persons = (
      <div>
      {this.state.persons.map((person, index) => {
        return (
          <Person name={person.name} 
                  age={person.age} 
                  key={person.id}
                  // PASS ID OF PERSON OBJECT TO EVENT HANDLER
                  changed={(event) => this.nameChangedHandler(event, person.id)} />
        )
      })}
      </div>
    );
  }
  
    return(
      <div>
        {persons}
      </div>
    )
  }
}
export default App;

Secondary Component

import React from 'react';
 
const person = (props) => {
  return (
    <div>
      <p>Hi! Im {props.name}</p>
      <input type="text" onChange={props.changed} value={props.name} />
    </div>
    );
}
export default App;