Reputation: 2339
I am trying to map a collection of keys to a list of toggle <Switch>
components. The state of each toggle switch is coming from redux. When I click on the <Switch>
, I expect the toggle state of the component to alternate.
I tried to call setState
in the onChange
handler on the <Switch>
, but its not working as expected. How can I write a function that will toggle the switch?
This is what I have so far:
{Object.keys(all_product).map((item, index) => {
console.log(all_product[item]);
let product = all_product[item];
this.state.activevalue = product.is_active;
let val;
product.is_active == 1 ? (val = true) : (val = false);
this.state = { checked: val };
return (
<tr>
<th scope="row">{product.id}</th>
<td>
<img
src={`/img/${product.code}.jpg`}
alt={product.name}
class="img-fluid dataTableImg"
/>
</td>
<td>{product.name}</td>
<td>{product.brand}</td>
<td>{product.quantity}</td>
<td>{product.unit_price}</td>
<td>
<Switch
onChange={() => {
this.setState({ checked: !val });
}}
checked={this.state.checked}
value={"A"}
/>
</td>
</tr>
);
})}
Upvotes: 3
Views: 6709
Reputation: 5270
In your handleChange of Switch, pass the index/id in your callback as well. see this
import React from "react";
import Switch from "react-switch";
import update from "react-update";
class App extends React.Component {
constructor(props) {
super(props);
//Assuming you've state in your component, that might as well be your redux state
this.state = {
all_products: [{ isActive: false, id: 1 }, { isActive: true, id: 2 }]
};
}
handleChange = (activeStatus, itemId) => {
const productIndex = this.state.all_products.findIndex(function(
item,
index
) {
return item.id === itemId;
});
let products = [...this.state.all_products];
let product = { ...products[productIndex] };
product.isActive = activeStatus;
products[productIndex] = product;
//fire a redux action if all_products is stored in redux state
this.setState({ all_products: products });
};
render() {
const that = this;
console.log(this.state.all_products);
return (
<div>
{this.state.all_products.map(function(item, index) {
return (
<Switch
checked={item.isActive}
onChange={isActive => that.handleChange(isActive, item.id)}
/>
);
})}
</div>
);
}
}
export default App;
Upvotes: 2
Reputation: 30360
If I understand your question correctly, you're getting the all_product
map from a redux store. The all_products
map contains an is_active
field on values to determine the initial state of each <Switch>
component and from there, the <Switch>
is then controlled by state internal to the enclosing component.
Assuming my understanding is correct, one solution might be to read and update the checked
prop of each <Switch>
component via key/values tracked in the enclosing component:
/* Read checked state */
let isChecked = this.state[ item ]
/* Update (toggle) checked state */
this.setState({ [ item ] : !isChecked })
Integrating that with your code could look like this:
{Object.keys(all_product).map((item, index) => {
/* Get product */
const product = all_product[item];
/* First try to get "checked value" from state */
let isChecked = this.state[ item ]
/* If isChecked fetched from state not present or
then default to the is_active value supplied by
your redux store */
if(typeof isChecked === 'undefined') {
isChecked = product.is_active;
}
return (
<tr>
<th scope="row">{product.id}</th>
<td>
<img
src={`/img/${product.code}.jpg`}
alt={product.name}
class="img-fluid dataTableImg"
/>
</td>
<td>{product.name}</td>
<td>{product.brand}</td>
<td>{product.quantity}</td>
<td>{product.unit_price}</td>
<td>
{ /* Use locally defined isChecked to set checked
prop, and update setState to set negated isChecked
for item by key */}
<Switch
onChange={() => {
this.setState({ [ item ]: !isChecked });
}}
checked={ isChecked }
value={"A"}
/>
</td>
</tr>
);
})}
Upvotes: 3