How to reference a component created with .map() by another component?

Viewed 130

My goal is to have a grid of toggle buttons that when selected their value is saved in an array. This array is used to map out another row of buttons.

When you select the button in the new row, it will unselect the corresponding toggle button, remove it's value from the array and have itself disappear as well.

None Selected:

Pre-selection

After Selection:

post-selection

The step not working (remove the selected button by clicking on it's value below):

enter image description here

I understand how to add and remove it from the array, my biggest hurdle is finding a way to reference the already selected toggle button to toggle it off.

My first thought was to use id like in css, but React components are not able to do this. After a lot of research I keep stumbling across useRef. I'm having trouble wrapping my brain around it and all of the toying around with it has not worked for my case.

Does anyone have any direction?

Code from Main

import Rows from "./playground2";

export default function PlaygroundMain(props){
    //This data can come in at different lengths
    const fetchData = [
        {
            info: "info1",
            data: {data1 : 11, data2 : 12, data3 : 13 }
        },
        {
            info: "info2",
            data: { data1 : 21, data2 : 22, data3 : 23 }
        },
        {
            info: "info3",
            data: { data1 : 31, data2 : 32, data3 : 33 }
        }
    ]

    const [selectedButtons, setSelectedButtons] = useState([])

    function handleButtonSelected(button) {
        const newButtons = selectedButtons
        if (!newButtons.includes(button)) {
            newButtons.push(button)
        } else {
            newButtons.splice(newButtons.indexOf(button), 1)
        }
        setSelectedButtons([...newButtons])
        console.log(selectedButtons)
    }

    return (
        <Box>
            {fetchData.map((row, index) => {
                return ( <Rows dataFromParent={row} selectHandler={handleButtonSelected}/> )
            })}
            {selectedButtons.map((button, index) => {
                return ( <Button> {button} </Button> )
            })}  
        </Box>
    )
}

Code from the rows:

import ClickableButton from "./playground3";

export default function Rows(props){   
    function handleButtonSelected(button) {
        props.selectHandler(button)
    }
    
    return (
        <Grid container>
            <Grid item>
                <ClickableButton text={props.dataFromParent.data.data1} selectHandler={handleButtonSelected}/>
            </Grid>
            <Grid item>
                <ClickableButton text={props.dataFromParent.data.data2} selectHandler={handleButtonSelected}/>
            </Grid>
            <Grid item>
                <ClickableButton text={props.dataFromParent.data.data3} selectHandler={handleButtonSelected}/>
            </Grid>
        </Grid>
    )
}

Code from the button:

export default function ClickableButton(props){

    const [selectedBool, setSelected] = useState(false);

    function buttonSelected(e) {
        setSelected(!selectedBool)
        props.selectHandler(props.text)
    }
    
    return (
        <ToggleButton
            selected={selectedBool}
            onChange={buttonSelected}
        >
                {props.text}
        </ToggleButton>
    )
}

Any advice is appreciated!

1 Answers

Instead of creating a separate state for your buttons, why not just re-use selectedButtons ?

With this, your toggle now depends on your selectedButtons array.

import React from "react";
import { ToggleButton } from "@mui/material";

export default function ClickableButton(props) {
  function buttonSelected(e) {
    props.selectHandler(props.text);
  }

  return (
    <ToggleButton
      selected={props.selectedButtons.includes(props.text) ? true : false}
      onChange={buttonSelected}
    >
      {props.text}
    </ToggleButton>
  );
}

Now deleting from that array would also untoggle the grid values.

  function handle(i) {
    setSelectedButtons([
      ...selectedButtons.slice(0, i),
      ...selectedButtons.slice(i + 1)
    ]);
  }

playground : https://codesandbox.io/s/naughty-bouman-jcvbuh?file=/src/App.js:826-961

Related