skip to Main Content

I have 1 parent(Container) and 2 (List, SelectedItem) child components, Initially I render all data to Container and send all data to list and first item as selectedItem to selected Item component. So ar so good

When a user clicks an item in the List component, it updates the selected item of the Parent through a function, the parent is able to update state, But it is not re-rendering selected item component.

List Component:


    import "./SelectedImage.css"

function ListSection({items, updateSelectedItem}) {
  return (
    <div className="list-section">
      <ul>
        {
          (items).map((item) => {
            return <li key={item.id} onClick={() => updateSelectedItem(item.id)}>{item.name}</li>
          })
        }
      </ul>
    </div>
  );
}

export default ListSection;


Container Component

    

    
import LeftSection from './LeftSection';
import logo from './logo.svg';
import RightSection from './RightSection ';
import SelectedItem from './SelectedItem';
import "./App.css";
import ListSection from './ListSection';
import { Component, useState } from 'react';

const products = [
  {id: 1, name: "Lime", size: ["large", "medium", "small"], category: "Juice", image: "lime-juice.jpg"},
  {id: 2, name: "Orange", size: ["large", "medium", "small"], category: "Juice", image: "orange-juice.jpg"},
  {id: 3, name: "Mango", size: ["large", "medium", "small"], category: "Juice", image: "mango-juice.jpg"},
]

function Container() {
  let [selectItem, setSelectItem] = useState(products[0]);

  function chooseSelectedItem(id) {
    let item = products.filter((value) => {
      console.log(value.id);
      return (value.id == id)
    })
    setSelectItem(item[0]);
    console.log(item[0]);
  }

  return (
    <div className="Container">
      <ListSection items={products} updateSelectedItem={chooseSelectedItem}/>
      <SelectedItem CurrentSelectedItem={selectItem}/>
    </div>
  );
}

export default Container;

SelectedItemComponent

import QuantityBar from "./QuantityBar";
import "./SelectedImage.css"
import { useState } from "react";

function SelectedItem({CurrentSelectedItem}) {
  let [item, setItem] = useState(CurrentSelectedItem);  

  return (
    <div className="selected-item">
      {/* <img src={item.image} className="selected-image" /> */}
      {item.name}
      {/* <QuantityBar itemCount={0} /> */}
    </div>
  );
}

export default SelectedItem;

2

Answers


  1. From your code, it seems your SelectedItem component is being rerendered (as you could assess by placing a console.log statement in the component), but the selected item is being cached by your useState:

      let [item, setItem] = useState(CurrentSelectedItem);  
    

    The first argument of useState is the initial value; this value is only read on the initial render (i.e. when the component is mounted). Any rerenders afterwards will not update the value of item. Since you’re reading the state’s value in {item.name}, you’ll always see the initial value. If you replace that line with {CurrentSelectedItem.name} (and maybe remove that useState), you will start seeing new value when an item is selected.

    Login or Signup to reply.
  2. Since you’re initializing the state using useState with the prop CurrentSelectedItem, any changes to CurrentSelectedItem won’t be reflected in the state of the component.

    You can use the useEffect hook to update the state of SelectedItem whenever CurrentSelectedItem changes:

    function SelectedItem({ CurrentSelectedItem }) {
      const [item, setItem] = useState(CurrentSelectedItem);
    
      useEffect(() => {
        setItem(CurrentSelectedItem);
      }, [CurrentSelectedItem]);
    
      ...
    }
    

    Or if SelectedItem is solely dependent on CurrentSelectedItem, you can remove the local state in SelectedItem and directly use CurrentSelectedItem as a prop, like

    function SelectedItem({ CurrentSelectedItem }) {
      return (
        <div className="selected-item">
          {/* <img src={CurrentSelectedItem.image} className="selected-image" /> */}
          {CurrentSelectedItem.name}
          {/* <QuantityBar itemCount={0} /> */}
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search