Pim
Pim

Reputation: 443

How to pass states/props between components

I have all the components listed in App.js. I'm kinda lost as on how to pass values from one component to the other.

Here's how it should work:

When an item is selected in the first component (ItemList), details are loaded in the second component (ItemDetails). Then in the second component if I click "add", it's added to the third component (ItemSelection).

How do I pass the clicked item in ItemList to ItemDetails, then pass it to ItemSelection on button click?

App component:

// dummy selectedItems array
let selectedItems = [
  {
    'name': 'item 3',
    'type': ['car'],
    'details': [ 'Detail 1', 'Detail 2', 'Detail 3' ]
  },
  {
    'name': 'item 6',
    'type': ['bike'],
    'details': [ 'Detail 5', 'Detail 1']
  }
]

<Container>
  <ItemList/>
  <ItemDetails/>
  <ItemSelection selected={selectedItems}/>
</Container>

ItemList component:

const LIST_ITEMS = require('./LIST_ITEMS.json');

const myList = 
  LIST_ITEMS.data.Items.map((Item) => (
    <li key={Item.id} onClick={() => loadItem(Item.name)}>
      {Item.name.toUpperCase()}
    </li>
  ))
;

function loadItem(name){
  console.log(name);
}

class ItemList extends Component {

  render() {
    return (
      <div id="item-list-wrapper">
        <h3>Select an Item</h3>
        <ul id="item-list">{myList}</ul>
      </div>
    );
  }
}

ItemDetails component:

import React, { Component } from 'react';

class ItemDetails extends Component {
  render() {
    <div id="item-details">
      // Additional details about the item
      <button>Add to selection</button>
    </div>
  }
}

ItemSelection component:

import React, { Component } from 'react';

class ItemSelection extends Component {
  render() {
    <div id="item-selection">
      // List selected items
      <h3>Selected Items</h3>
      <div className="item-slot">
        {this.props.selected[0] ? (
            <div className="selected-details">
                <h4>{this.props.selected[0].name}</h4>
                <ul>
                  <li>{this.props.selected[0].details[0]}</li>
                  <li>{this.props.selected[0].details[1]}</li>
                  <li>{this.props.selected[0].details[2]}</li>
                </ul>
            </div>
        ) : (
          <p>empty</p>
        )}
    </div>
    </div>
  }
}

Upvotes: 0

Views: 119

Answers (1)

Alvin S. Lee
Alvin S. Lee

Reputation: 5182

First, I would recommend the article, "Lifting State Up", as referenced by @codekaizer in the comments.

The main principle that you want to take from the article is this

There should be a single "source of truth" for any data that changes in a React application.

For your situation, that single "source of truth" should be your App component - the one that talks to ItemList, ItemDetails, and ItemSelection.

The flow of communication between components should look like this:

ItemList

  • What items should I display? App will tell me in a prop.
  • What should I do when one of my list items is clicked? App will tell me in a prop.

ItemDetails

  • Which item should I display the details for? App will tell me in a prop
  • What should I do when the "select this item" button is clicked? App will tell me in a prop.

ItemSelection

  • What items should I display? App will tell me in a prop.

App

  • What items should I tell ItemList to display? I'll pass on what I get from LIST_ITEMS.json
  • Which item should I tell ItemDetails to display the details for? I'll maintain this in my state as currentItem. Initially, no item's details will be displayed.
    • If one of the items in ItemList is clicked, then I need to change my state's currentItem to be the item clicked. (HINT: App needs a function, and this function's callback needs to be passed to ItemList)
  • What items should I tell ItemSelection to display? I'll maintain this in my state as selectedItems. Initially, there will be no items selected.
    • If the item currently shown in ItemDetails is "selected", then I need to add that currently displayed item to my array of selectedItems. (HINT: App needs a function, and this function's callback needs to be passed to ItemDetails)

Key Takeaways

  • App should maintain a state with the currentItem to be displayed in item details and the selectedItems which will show up in the item selection list.
  • App needs a few functions that manipulate the currentItem and the selectedItems states.
  • App needs to pass those function callbacks to the children.
  • The children, essentially, act as display dummies: "Just tell me what I need to display, and tell me what I should do if someone clicks this thing over here."

I've coded up a basic example of how this all looks in action. By studying it and applying it to your situation, this should give you a better understanding of how to get components to "talk to each other."

Edit maintaining state between components

Upvotes: 2

Related Questions