Reputation: 4349
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?
Upvotes: 1
Views: 1464
Reputation: 203522
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>
);
})}
Ok, I've gathered that you:
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>
);
})}
Upvotes: 2
Reputation: 4938
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)}
/>
);
}
Upvotes: 0