Home > Mobile >  How to manage props of a list of components in React?
How to manage props of a list of components in React?

Time:08-27

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?

CodePudding user response:

Since we do not have the visibility of how ListChild works, I assume that it turns true or false to specific items.

Since you want to change the state once then my advice would be to run the loop on parent element, access collapsed property and turn all of them to be false.

Also, please share the schema of the objects as well childObjects and how the whole functionality is actually working so that we all have better visual of the code to provide better and more accurate answer.

CodePudding user response:

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;
  • Related