1

I am trying to implement a enable and disable toggle button on a list of rows from a data map returned from a function to fetch results from a backend

issue is i need to set defaultChecked to whatever value of el.enabled is within the map of json data but have been un-successful

here is what the data map looks like

data = [
    {
        "id": 1,
        "enabled": true,
    },
    {
        "id": 2,
        "enabled": false,
    },
    {
        "id": 3,
        "enabled": true,
    },
    {
        "id": 4,
        "enabled": false,
    }
]

data is derived from below function that fetched value from API backend

const [data, setData] = useState([]);
    
const fetchData = async () => {
   let json = await getData();
   setData(json);
}

and here is the updateToggle function that enabled or disabled each row

const [statusMode, setStatusMode] = useState();

const updateToggle = async (rowID) => {
    // rowID = el.id
    const updateData = {'id': rowID}

    if ( statusMode == true ) {
      const request = await disable(updateData);
      setStatusMode(false)
    }
    
    if ( statusMode == false ) {
      const request = await enable(updateData);
      setStatusMode(true)
    }
};

and here is what i have that is not working but shows what am trying to achieve

{data.map((el, k) => {
    return (
        <div>
          <div class="checkbox">
            <label class="switch">
                <input type="checkbox" defaultChecked={setStatusMode(el.enabled, k)} onClick={() => updateToggle(el.id, k)} />
            </label>
          </div> 
        </div>
    );
  })}

issue is happening right here defaultChecked={setStatusMode(el.enabled, k)} as i want to set the value to whatever i get from el.enabled for the specific row

error am getting at the moment is

Too many re-renders. React limits the number of renders to prevent an infinite loop.

how can i achieve this? or is there a better way to go about this?

1
  • You can pass the data as the initial value for useState. Commented Aug 18, 2021 at 5:55

2 Answers 2

2

The issue is that you are passing and immediately invoking the state updater function, leading to the render looping.

const [statusMode, setStatusMode] = useState();

{data.map((el, k) => {
  return (
    <div>
      <div class="checkbox">
        <label class="switch">
          <input
            type="checkbox"
            defaultChecked={setStatusMode(el.enabled, k)} // <-- updates state!!
            onClick={() => updateToggle(el.id, k)}
          />
        </label>
      </div> 
    </div>
  );
})}

You should set the defaultChecked value to that of the values being mapped over. Let the onClick handler handle updating the state.

const [statusMode, setStatusMode] = useState();

{data.map((el, k) => {
  return (
    <div key={el.id}>
      <div class="checkbox">
        <label class="switch">
          <input
            type="checkbox"
            defaultChecked={el.enabled} // <-- el.enabled
            onClick={() => updateToggle(el.id, k)}
          />
        </label>
      </div> 
    </div>
  );
})}

Update

Ok, I've gathered that you:

  1. Asynchronously fetch and store in state some "data".
  2. You render this data into checkboxes.
  3. You want to toggle the state and call some endpoints.

Code

const [data, setData] = useState([]);

const fetchData = async () => {
  const json = await getData();
  setData(json);
};

const updateToggle = async (rowID) => {
  // rowID = el.id
  const updateData = {'id': rowID}

  // find elements first
  const dataEl = data.find(el => el.id === rowID);

  // conditionally enable/disable in backend
  if (dataEl.enabled) {
    const request = await disable(updateData);
  } else {
    const request = await enable(updateData);
  }

  // update local state
  setData(data => data.map(el => el.id === rowId
    ? { ...el, enabled: !el.enabled }
    : el
  ));
};

...

{statusMode.map((el) => {
  return (
    <div key={el.id}>
      <div class="checkbox">
        <label class="switch">
          <input
            type="checkbox"
            checked={el.enabled}
            onClick={() => updateToggle(el.id)}
          />
        </label>
      </div> 
    </div>
  );
})}
Sign up to request clarification or add additional context in comments.

14 Comments

will this work if data is also a state from a function that calls API backend? i only put how the data looks, it is not static const..it is state from a fetch function
@uberrebu Not sure I follow, but sure, it should work at least once if you are just setting the default checked value of an input. Have you missed including relevant details and code in your question? What function? What API? stackoverflow.com/help/minimal-reproducible-example I'm gathering now that data is asynchronously updated and you're asking how to set the defaultChecked prop after the fact?
added more details in the question...so it did get the data actually but does not work when i try to enable or disable..nothing happens...i added all the details..and the updateToggle function also
current issue now is the updateToggle function is not working at all...what am i missing there? or what do i have wrong?
tested and worked!!! i fixed the mistakes and accepted as answer..thanks a lot..really appreciate your help
|
0

You could use the enabled data as a prop and assign it to the initial state of the component

You could see the working example here -> https://codesandbox.io/s/clever-cookies-dn7z7?file=/src/App.js:0-873

import { useState } from "react";
import "./styles.css";

const data = [
  {
    id: 1,
    enabled: true
  },
  {
    id: 2,
    enabled: false
  },
  {
    id: 3,
    enabled: true
  },
  {
    id: 4,
    enabled: false
  }
];

export default function App() {
  return (
    <div className="App">
      {data.map((el, k) => {
        return (
          <div>
            <div class="checkbox">
              <label class="switch">
                <SingleCheckbox singleData={el} key={el.id} />
              </label>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function SingleCheckbox({ singleData }) {
  const [statusMode, setStatusMode] = useState(singleData.enabled);

  return (
    <input
      type="checkbox"
      defaultChecked={statusMode}
      onClick={() => setStatusMode(!statusMode)}
    />
  );
}

Comments

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.