Victor2748
Victor2748

Reputation: 4199

How to manage props of a list of components in React?

I am trying to create an ObjectList component, which would contain a list of Children.

const MyList = ({childObjects}) => {
    [objects, setObjects] = useState(childObjects)

    ...

    return (
        <div>
            {childObjects.map((obj, idx) => (
                <ListChild
                    obj={obj}
                    key={idx}
                    collapsed={false}
                />
            ))}
        </div>
    )
}

export default MyList

Each Child has a collapsed property, which toggles its visibility. I am trying to have a Collapse All button on a parent level which will toggle the collapsed property of all of its children. However, it must only change their prop once, without binding them all to the same state. I was thinking of having a list of refs, one for each child and to enumerate over it, but not sure if it is a sound idea from design perspective.

How can I reference a dynamic list of child components and manage their state?

Alternatively, is there a better approach to my problem?

Upvotes: 0

Views: 412

Answers (1)

Paulo Fernando
Paulo Fernando

Reputation: 3660

I am new to react, probably there is a better way, but the code below does what you explained, I used only 1 state to control all the objects and another state to control if all are collapsed.

Index.jsx

import MyList from "./MyList";

function Index() {
  const objList = [
    { data: "Obj 1", id: 1, collapsed: false },
    { data: "Obj 2", id: 2, collapsed: false },
    { data: "Obj 3", id: 3, collapsed: false },
    { data: "Obj 4", id: 4, collapsed: false },
    { data: "Obj 5", id: 5, collapsed: false },
    { data: "Obj 6", id: 6, collapsed: false },
  ];

  return <MyList childObjects={objList}></MyList>;
}

export default Index;

MyList.jsx

import { useState } from "react";
import ListChild from "./ListChild";

const MyList = ({ childObjects }) => {
  const [objects, setObjects] = useState(childObjects);
  const [allCollapsed, setallCollapsed] = useState(false);

  const handleCollapseAll = () => {
    allCollapsed = !allCollapsed;

    for (const obj of objects) {
      obj.collapsed = allCollapsed;
    }
    setallCollapsed(allCollapsed);
    setObjects([...objects]);
  };

  return (
    <div>
      <button onClick={handleCollapseAll}>Collapse All</button>

      <br />
      <br />

      {objects.map((obj) => {
        return (
          <ListChild
            obj={obj.data}
            id={obj.id}
            key={obj.id}
            collapsed={obj.collapsed}
            state={objects}
            setState={setObjects}
          />
        );
      })}
    </div>
  );
};

export default MyList;

ListChild.jsx

function ListChild(props) {
  const { obj, id, collapsed, state, setState } = props;

  const handleCollapse = (id) => {
    console.log("ID", id);

    for (const obj of state) {
      if (obj.id == id) {
        obj.collapsed = !obj.collapsed;
      }
    }
    setState([...state]);
  };

  return (
    <div>
      {obj} {collapsed ? "COLLAPSED!" : ""}
      <button
        onClick={() => {
          handleCollapse(id);
        }}
      >
        Collapse This
      </button>
    </div>
  );
}

export default ListChild;

Upvotes: 2

Related Questions