1

I have an array of objects. So for every object, which has subItems, I'm trying to add a button to it. On click of the particular button, the name of the particular button should toggle between 'Expand' and 'Hide'. I'm displaying them using map.

export default function App() {

  const [button,setButton] = useState([
    {pin: 'Expand', id: 0},
    {pin: 'Expand', id: 1},
    {pin: 'Expand', id: 2},
  ]);

  const dataObj = [
    {
      title: 'Home'
    },
    {
      title: 'Service',
      subItems: ['cooking','sleeping']
    },
    {
      title: 'Contact',
      subItems: ['phone','mobile']
    }
  ];

  const expandFunc = (ind) => {
   // toggle logic here
  }
  return (
    <div className="App">
      {
        dataObj.map((arr,ind) => (
          <div>
            <span>{arr.title}:</span>
            {
              // console.log(ind)
              arr.subItems && 
              <button onClick={() => expandFunc(ind)}>{button[ind].pin}</button>
            }
          </div>
        ))
      }
    </div>
  );
}

This is how the output looks - enter image description here

If I click on service button, then the button name should toggle between 'expand' and 'hide'. Could someone help me with this?

3 Answers 3

2

You need to update your state by determining new pin based on current state, try using Array.map:

const expandFunc = (ind) => {
    const togglePin = oldPin => oldPin === "Expand" ? "Hide" : "Expand";
    const updatedButtons = button.map((btn, index) => 
        ind === index ? { ...btn, pin: togglePin(btn.pin) } : btn);
    setButton(updatedButtons);
}
Sign up to request clarification or add additional context in comments.

Comments

2

You can use something like this, I'll also suggest combining dataObj into button state, and using key while mapping elements in React helps to skip them in the rendering process making your site faster.

export default function App() {

  const [button, setButton] = useState([{
      expanded: false,
      id: 0
    },
    {
      expanded: false,
      id: 1
    },
    {
      expanded: false,
      id: 2
    },
  ]);

  const dataObj = [{
      title: 'Home'
    },
    {
      title: 'Service',
      subItems: ['cooking', 'sleeping']
    },
    {
      title: 'Contact',
      subItems: ['phone', 'mobile']
    }
  ];

  const toggleExpandFunc = useCallback((ind) => {
    // toggle logic here
    setButton([...button.map(btn => btn.id === ind ? { ...btn,
      expanded: !btn.expanded
    } : btn)]);
  }, [button]);
  
  return ( <
    div className = "App" > {
      dataObj.map((arr, ind) => ( <
        div >
        <
        span > {
          arr.title
        }: < /span> {
          // console.log(ind)
          arr.subItems &&
            <
            button onClick = {
              () => toggleExpandFunc(ind)
            } > {
              button[ind].expanded ? 'Expanded' : 'Hide'
            } < /button>
        } <
        /div>
      ))
    } <
    /div>
  );
}

Comments

-1

You can also need another state like Toggle and expnadFunc can be handled like this;

const expandFunc = (ind) => {
    let tmp = [...button];
    tmp.map((arr, index) => {
      if (index === ind) {
        return (arr.pin = arr.pin === 'Toggle' ? 'Expand' : 'Toggle');
      }
      return arr;
    });
    setButton(tmp);
  };

1 Comment

this creates two copies of the button array. use @mickl or vivek's solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.