I've a object:
{
"products": [
{
"id": 1,
"category": "Milk & meat",
"products": {
"product1": ["Name", "Recipe", "Photo"]
}
}
}
and it's mapped like that:
return (
<div className="box list">
{this.props.products
.map((product, ind) =>
<div key={ind}>
<h2>{product.category}</h2>
{Object.values(product.products).map(name => <li onClick={this.props.handleClickedProduct}>{name[0]}</li>)}
</div>)}
</div>
)
The onClick method passes the product name ([0] in array) to other component. It does it like that:
handleClickedProduct = (e) => {
this.setState({ clickedProduct: e.target.innerHTML });
}
How cane I setState [1] and [2] from the same array?
I want to pass forward the product name and keep in state the recipe and photo.
Thanks,
Kuba
class Example extends React.Component {
products = [
{
id: 1,
category: "Milk & meat",
products: {
product1: ["Name", "Recipe", "Photo"]
}
},
{
id: 2,
category: "Milk & bread",
products: {
product1: ["Name", "Recipe", "Photo"]
}
}
]
state = {
clickedProduct: null
}
handleClick = (product) => (e) => {
this.props.onClick(product)
}
render() {
return (
<div className="box list">
{this.products.map((product, ind) =>
<div key={ind}>
<h2>{product.category}</h2>
<ul>
{Object.values(product.products)
.map(pr => <li onClick={this.handleClick(pr)}>{pr[0]}</li>)}
</ul>
</div>)
}
</div>
)
}
}
class Handler extends React.Component {
handler = (e) => {
console.log(e)
}
render () {
return <Example onClick={this.handler}/>
}
}
ReactDOM.render(
<Handler />,
document.getElementById('container')
);
Change handleClickedProduct to be
handleClickedProduct = (name) => (e) => {
this.setState({ clickedProduct: e.target.innerHTML });}
and inside your map you can just do this.handleClickedProduct(product.products) and use it inside the handleClickedProduct function.
Related
I am trying to print a nested array (sublist) under object element (value) from the state.list. I tried but did not get the expected result I want. I made two components named Orderlist and Item which hold the nested array and value elements. I could not find where I am doing wrong. Sorry! I am in the learning stage and working on a super small project. Every help would be appreciated.
import React from "react";
import "./styles.css";
const Item = (props) => {
return props.list.map((item)=><li>{item.sublist}</li>);
};
const Orderlist = (props) => {
return props.list.map((element) => (
<ol>
{element.value}
<Item list = {props.list} />
</ol>
));
};
class App extends React.Component {
state = {
list: [
{ value: "Fruit", sublist: ["Banana", "Apple", "Graps"] },
{ value: "Vegetable", sublist: ["Carrat", "Potato", "Mushroom"] },
{ value: "Sports", sublist: ["Cricket", "Badminton", "Football"] },
{ value: "Continent", sublist: ["Asia", "Europe", "Africa"] }
]
};
render() {
return <Orderlist list={this.state.list} />;
}
}
export default App;
outcome got ........
Fruit
BananaAppleGraps
CarratPotatoMushroom
CricketBadmintonFootball
AsiaEuropeAfrica
Vegetable
BananaAppleGraps
CarratPotatoMushroom
CricketBadmintonFootball
AsiaEuropeAfrica
Sports
BananaAppleGraps
CarratPotatoMushroom
CricketBadmintonFootball
AsiaEuropeAfrica
Continent
BananaAppleGraps
CarratPotatoMushroom
CricketBadmintonFootball
AsiaEuropeAfrica
There were two mistakes:
You need to pass element.sublist as list prop to Item instead of props.list:
<Item list={element.sublist} />
List item should be just item instead of item.sublist:
<li>{item}</li>
const Item = (props) => {
return props.list.map((item, index) => <li key={index}>{item}</li>);
};
const Orderlist = (props) => {
return props.list.map((element, idx) => (
<ol key={idx}>
{element.value}
<Item list={element.sublist} />
</ol>
));
};
class App extends React.Component {
state = {
list: [
{ value: "Fruit", sublist: ["Banana", "Apple", "Graps"] },
{ value: "Vegetable", sublist: ["Carrat", "Potato", "Mushroom"] },
{ value: "Sports", sublist: ["Cricket", "Badminton", "Football"] },
{ value: "Continent", sublist: ["Asia", "Europe", "Africa"] }
]
};
render() {
return <Orderlist list={this.state.list} />;
}
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
https://codesandbox.io/s/dazzling-golick-0ie3qy?file=/src/App.js
{list.map((item, index) => (
<>
<li>{item.value}</li>
{item?.sublist?.map((subitem, index) => (
<>
<li>{subitem}</li>
</>
))}
</>
))}
try this :
const Item = (props) => {
return props.list.map((item)=><li>{item}</li>);
};
const Orderlist = (props) => {
return props.list.map((element) => (
<ol>
{element.value}
<Item list = {element.sublist} />
</ol>
))
I'm now leaning react and having a lot of fun with, but also having my first issue than I cannot solved by myself.
I would like to use a child component to filter on his parent list. I mean I would like to use a child component to filter a list from his parent.. I hope my code would be more understandable than my explications...
Does anyone can explain how should I use onclick in both class and maybe optimize my code ? Thanks
product.jsx
class Items extends Component {
state = {
count: 0,
carbondioxide: [
{ key: 90, name: "All", value: "All" },
{ key: 91, name: "Still Water", value: "Still Water" },
{ key: 92, name: "Sparkling Water", value: "Sparkling Water" },
],
brands: [
{
key: 0,
name: "Fountain",
category: "Still Water",
},
{
key: 1,
name: "Kitchen",
category: "Sparkling Water",
},
{
key: 2,
name: "Shower",
category: "Still Water",
},
],
filterBrands: [],
};
componentDidMount() {
this.setState({
filterBrands: this.state.brands,
});
}
handleClick = (name) => {
let filterBrands = [];
if (name === "All") {
filterBrands = this.state.brands;
} else {
filterBrands = this.state.brands.filter(
(brands) => brands.category === name
);
}
this.setState({ filterBrands });
};
}
render() {
return (
<div className="ctg-flex">
<GroupButtonFilter
carbondioxide={this.state.carbondioxide}
onClick={this.handleClick.bind(this, name)} //filterBrands onclick
//onClick={() => {
// this.handleClick.bind(this, this.state.carbondioxide.name);
//}}
/>
{this.state.filterBrands.map((id, brands) => (
<Item
key={id.key}
dataImg={id.imageUrl}
dataText={id.name}
dataPrice={id.price}
/>
))}
</div>
);
}
}
export default Items;
and GroupeButtonFilter.jsx
class GroupButtonFilter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="group-button">
{this.props.carbondioxide.map(({ name, value }) => (
<Button
key={this.props.carbondioxide.key}
value={this.props.carbondioxide.value}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={this.props.onClicktest} //filterBrands onclick
>
{name}
</Button>
))}
</div>
);
}
}
There are couple of issue on your code.
You are binding your:
onClick={() => {
this.handleClick.bind(this, this.state.carbondioxide.name);
}}
and your handleClick is using arrow function so you can remove bind from this i.e
onClick={() => {
this.handleClick( this.state.carbondioxide.name);
}}
Still its not correct. which is our second point
In GroupButtonFilter you are expecting onClicktest and while passing in GroupButtonFilter you are sending onClick this can reduce to this:
<Button
key={this.props.carbondioxide.key}
value={this.props.carbondioxide.value}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={this.props.onClicktest} //filterBrands onclick
>
{name}
</Button>
You need to pass the value that button is clicked but in onClick you are sending carbondiooxide name. You need to do this. Inside GroupFilter:
<button
key={this.props.carbondioxide.key}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={() => this.props.onClicktest(name)} //filterBrands onclick
>
{name}
</button>
Here is complete code:
import React, { Component } from "react";
import "./styles.css";
class GroupButtonFilter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="group-button">
{this.props.carbondioxide.map(({ name, value }) => (
<button
key={this.props.carbondioxide.key}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={() => this.props.onClicktest(name)} //filterBrands onclick
>
{name}
</button>
))}
</div>
);
}
}
class Items extends Component {
state = {
count: 0,
carbondioxide: [
{ key: 90, name: "All", value: "All" },
{ key: 91, name: "Still Water", value: "Still Water" },
{ key: 92, name: "Sparkling Water", value: "Sparkling Water" }
],
brands: [
{
key: 0,
name: "Fountain",
category: "Still Water"
},
{
key: 1,
name: "Kitchen",
category: "Sparkling Water"
},
{
key: 2,
name: "Shower",
category: "Still Water"
}
],
filterBrands: []
};
componentDidMount() {
this.setState({
filterBrands: this.state.brands
});
}
handleClick = (name) => {
console.log(name);
let filterBrands = [];
if (name === "All") {
filterBrands = this.state.brands;
} else {
filterBrands = this.state.brands.filter(
(brands) => brands.category === name
);
}
this.setState({ filterBrands });
};
render() {
return (
<div className="ctg-flex">
<GroupButtonFilter
carbondioxide={this.state.carbondioxide}
onClicktest={this.handleClick}
// onClicktest={this.handleClick.bind(
// this.state.carbondioxide.name,
// this.name
// )}
/>
{this.state.filterBrands.map((id, brands) => (
<div key={id.name}>{id.name}</div>
))}
</div>
);
}
}
export default function App() {
return (
<div className="App">
<Items />
</div>
);
}
here is the demo:https://codesandbox.io/s/affectionate-fire-zcqc1?file=/src/App.js:0-2168
write a function in your parent component
handleClick = () => {
/// do your filtering
}
pass this handleClick to your child component
<GroupButtonFilter handleClickInParent ={this.handleClick} />
....
</GroupButtonFilter>
then inside your child component
<Button. onClick={() => this.props.handleClick())}>
</Button>
The code below shows each user info on users list button click.
Now I want fetch each users record from database on users list button click.
In the open() function, I have implemented the code below
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
}
In class OpenedUser(), I have initialize in the constructor the code below
chatData: []
In the render method have implemented the code
<b> Load Message from Database for each user ({this.state.chatData1})</b>
<div>
{this.state.chatData.map((pere, i) => (<li key={i}>{pere.lastname} - {pere.id}----- {pere.username}</li>))}
</div>
Here is my Issue:
My problem is that the Axios Api is getting the result but am not seeing any result in the render method.
but I can see it in the console as per code below
Array(1)
0: {id: "1", firstname: "faco", lastname: "facoyo"}
length: 1
Here is an example of json api response.
[{"id":"1","firstname":"faco","lastname":"facoyo"}]
Here is the full code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import { Link } from 'react-router-dom';
import axios from 'axios';
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button onClick={() => this.open(this.props.data.id,this.props.data.name)}>{this.props.data.name}</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
chatData: [],
hidden: false,
};
}
componentDidMount(){
} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b> Load Message from Database for each user ({this.state.chatData1}) </b>
<div>
{this.state.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</div>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
],
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/apidb_react/search_data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
// end axios api call
this.setState((prevState) => ({
activeIds: prevState.activeIds.find((user) => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
}
close = id => {
this.setState((prevState) => ({
activeIds: prevState.activeIds.filter((user) => user !== id),
}));
};
renderUser = (id) => {
const user = this.state.data.find((user) => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser key={user.id} data={user} close={this.close}/>
)
}
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map((id) => this.renderUser(id)) }
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
The problem is you're making the request in the App component and storing in state but you're trying to access the state in a child component so it will never actually read the data.
To fix this you need to pass in the chat data via prop
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
Note: In my runnable example, I've replaced your api endpoint with a mock api promise.
const mockApi = () => {
return new Promise((resolve, reject) => {
const json = [{ id: "1", firstname: "faco", lastname: "facoyo" }];
resolve(json);
});
};
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button
onClick={() => this.open(this.props.data.id, this.props.data.name)}
>
{this.props.data.name}
</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
hidden: false
};
}
componentDidMount() {} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b>
{" "}
Load Message from Database for each user ({this.state.chatData1}
){" "}
</b>
<ul>
{this.props.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
chatData: [],
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
]
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id, name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: "id",
uname: "name"
};
// this.setState({ loading_image: true }, () => {
// axios
// .post("http://localhost/apidb_react/search_data.php", { user_data })
// .then(response => {
// this.setState({
// chatData1: response.data[0].id,
// chatData: response.data,
// loading_image: false
// });
// console.log(this.state.chatData);
// alert(this.state.chatData1);
// })
// .catch(error => {
// console.log(error);
// });
// });
this.setState({ loading_image: true }, () => {
mockApi().then(data => {
this.setState({
chatData1: data[0].id,
chatData: data,
loading_image: false
});
});
});
// end axios api call
this.setState(prevState => ({
activeIds: prevState.activeIds.find(user => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
};
close = id => {
this.setState(prevState => ({
activeIds: prevState.activeIds.filter(user => user !== id)
}));
};
renderUser = id => {
const user = this.state.data.find(user => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
);
};
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map(id => this.renderUser(id))}
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I see a few missing points in your code namely you are using li without ul which is a kind of invalid markup, then you have mapping for .username which is undefined field according to response which may also throw error.
Reactjs not updating the new value of product_number. I knew that similar question has been asked but am having hard time trying to resolve this.
The Reactjs code below displays provisions records from the arrays.
Now I need to update and replace the value the product_number from 001 to 006.
To this effect, I have added an update button which fetch the product_number from the Axios Call.
My problem is that product_number is not updated with 006 when the button is clicked.
Here is the json response of Axios Call for product_number updates
product_number.json
[{"product_number":"006"}]
Here is the code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import axios from 'axios';
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: false
};
}
componentDidMount() {
this.setState({
data: [
{"provision_id":"1","provision":"Milk","category":[{"category_id":"1","category_price":"100 USD","product":[{"product_id":"1","product_number":"001"}] }]}
],
});
}
// Get and update New Product number of Milk
handleNewProductNumber(prod_id) {
alert(prod_id);
const prod_data = {
prod_id: prod_id};
axios
.get("http://localhost/provision/product_number.json", { prod_data })
.then(response => {
const newData = this.state.data.map(store => {
//if (product.product_id !== prod_id) return product;
return {
...store,
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
};
});
this.setState(state => ({
data: newData
}));
console.log(response.data[0].category_price);
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<span>
<label>
<ul>
{this.state.data.map((store) => {
return (
<div key={store.provision_id}>
<div><h1>Provision Store</h1> <br />
<b> Product: </b>{store.provision}
</div>
{store.category && store.category.map((cat) => {
return (
<div key={cat.category_id}>
<div><b>Prices:</b> {cat.category_price}
</div>
{cat.product && cat.product.map((prod) => <div key={prod.product_id}>
<b>Product Number:</b> #{prod.product_number}
<br />
<input
type="button"
value="Get & Update New Product Number"
onClick={() => this.handleNewProductNumber(prod.product_id)}
/>
</div>)}
</div>
)
})}
</div>
)
})}
</ul>
</label>
</span>
);
}
}
Updated Section using map function
return {
...store,
category: store.category.map(
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
})
})
};
The problem is the same of the other question, you have an array of object, with inside another array of objects, in your state:
data: [
{
"provision_id": "1",
"provision": "Milk",
"category": [
{
"category_id": "1",
"category_price": "100 USD",
"product": [
{
"product_id": "1",
"product_number": "001"
}
]
}
]
}
]
To update the inner level, you have to traverse all the state tree:
return {
...store,
category: [{
...store.category,
product: [{
...store.category[0].product,
product_number: response.data[0].product_number
}]
}]
};
Edit after... well, your edit
Your updated piece of code isn't valid syntax:
return {
...store,
category: store.category.map(
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
})
};
The first store.category.map call takes a function which will be called with a single category as an argument.
You have to spread the category prior to shadow the product property:
return {
...store,
category: store.category.map(
category => ({
...category,
product: category.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
})
)
};
I am having 4 buttons each button have name id and selected boolean flag.
What I am trying to achieve is, on click of button, boolean button flag should be changed of that particular button. For this, I need to setState in map function for that particular button Id.
My issue is I am unable to setState in map function for that particular clicked button, its btnSelected should be changed
My aim is to create a multi-select deselect button.Its kind of interest selection for the user and based on that reflect the UI as well my array. Here is my code.
Thanks in anticipation.
import React, { Component } from "react";
import { Redirect } from "react-router-dom";
export default class Test extends Component {
constructor(props, context) {
super(props, context);
this.handleChange = this.handleChange.bind(this);
this.state = {
value: "",
numbers: [1, 2, 3, 4, 5],
posts: [
{
id: 1,
topic: "Animal",
btnSelected: false
},
{
id: 2,
topic: "Food",
btnSelected: false
},
{
id: 3,
topic: "Planet",
btnSelected: false
},
{ id: 4, topic: "Nature", btnSelected: false }
],
allInterest: []
};
}
handleChange(e) {
//console.log(e.target.value);
const name = e.target.name;
const value = e.target.value;
this.setState({ [name]: value });
}
getInterest(id) {
this.state.posts.map(post => {
if (id === post.id) {
//How to setState of post only btnSelected should change
}
});
console.log(this.state.allInterest);
if (this.state.allInterest.length > 0) {
console.log("Yes we exits");
} else {
console.log(id);
this.setState(
{
allInterest: this.state.allInterest.concat(id)
},
function() {
console.log(this.state);
}
);
}
}
render() {
return (
<div>
{this.state.posts.map((posts, index) => (
<li
key={"tab" + index}
class="btn btn-default"
onClick={() => this.getInterest(posts.id)}
>
{posts.topic}
<Glyphicon
glyph={posts.btnSelected === true ? "ok-sign" : "remove-circle"}
/>
</li>
))}
</div>
);
}
}
Here's how you do something like this:
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (e) => {
const { posts } = this.state;
const { id } = e.target;
posts[id].selected = !this.state.posts[id].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="radio" id={i} key={i} checked={p.selected} onClick={this.handleClick} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here.
You can do this by passing the index from the map into each button's handleClick function, which would then return another function that can be triggered by an onClick event.
In contrast to Colin Ricardo's answer, this approach avoids adding an id prop onto each child of the map function that is only used for determining the index in the handleClick. I've modified Colin's example here to show the comparison. Notice the event parameter is no longer necessary.
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (index) => () => {
const { posts } = this.state;
posts[index].selected = !this.state.posts[index].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="checkbox" key={i} checked={p.selected} onClick={this.handleClick(i)} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here