I have a problem with propagation in react.
I hace this method that render div-tags with p-tags within:
private renderTags(tag: Tags, index: number) {
return <div>
<div onClick={(e) => { e.stopPropagation(); this.collectTags(tag); }}>
<p className={styles.tag}># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></p>
</div>
</div>
}
that method is called from the render like this:
<div className={styles.tagsContainer}>
{this.state.items.slice(0, 12).map((w, index) => this.renderTags(w, index))}
</div>
As you see the renderTags method calls for each items in the array.
the idea with the first method is that when a user click on one of the elements that element is sent to an array, the problem is that when I click in one of these elements all the elements sends to the array. I tested by adding a class name to the clicked element just for checking reason, and i can see that the same behavior arises, when I click in one of the elements all the elements get the class name.
how can I stop this propagation?. by the way this is the method that hear for the click and put the clicked element in the array:
private collectTags(newTag: Tags): any {
//this.setState({ savingSettings: true, tagActive: true });
let selectedTags: Tags[] = this.state.selectedTags;
selectedTags.push(newTag);
this.setState({
selectedTags: selectedTags,
hideSaveButton: false
});
return selectedTags;
}
UPDATE
Better I post the entire code:
import * as React from 'react';
import { CacheManager } from "../../common/CacheManager";
import { ITagsDataProvider } from "../../interfaces/ITagsDataProvider";
import Tags from "./Tags";
import styles from './TagsContainer.module.scss';
import { Dialog, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
export interface ITagsContainerProps {
provider: ITagsDataProvider;
}
export interface ITagsContainerState {
items: Tags[];
allTags: Tags[];
selectedTags: Tags[];
savingSettings: boolean;
currentTagsIndex: number;
activeTile: number;
hideDialog: boolean;
hideSaveButton: boolean;
}
export default class TagsContainer extends React.Component<ITagsContainerProps, ITagsContainerState> {
private readonly cacheKey = "TagsLinks";
constructor(props: ITagsContainerProps) {
super(props);
this.state = {
items: [],
allTags: [],
selectedTags: [],
savingSettings: false,
currentTagsIndex: -1,
activeTile: -1,
hideDialog: true,
hideSaveButton: true
}
}
public componentDidMount(): void {
var cacheManager = new CacheManager();
var cachedValue = cacheManager.get(this.cacheKey);
//If there are cached values update the state
if (cachedValue) {
this.setState({
items: cachedValue,
allTags: [],
savingSettings: false,
currentTagsIndex: -1
});
return;
}
this.props.provider.getAllTags().then((tags) => {
if (tags != null) {
cacheManager.set(this.cacheKey, tags);
}
this.setState({
items: tags,
allTags: [],
});
});
}
private renderTags(tag: Tags, index: number) {
return <div>
<div onClick={(e) => this.onTagClick(tag, e)}>
<p className={styles.tag}># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></p>
</div>
</div>
}
private onTagClick(tag: Tags, e: React.MouseEvent<HTMLDivElement>) {
e.stopPropagation();
this.collectTags(tag);
}
private collectTags(newTag: Tags): any {
this.setState({
selectedTags: {
...this.state.selectedTags,
newTag
},
hideSaveButton: false
});
}
private saveSettings(): void {
let sTags = this.state.selectedTags;
this.setState({
items: sTags
});
console.log('SELECTED TAG ' + this.state.items);
var cacheManager = new CacheManager();
cacheManager.set(this.cacheKey, sTags);
this.props.provider.saveSettingsData(sTags).then(() => {
this.setState({
savingSettings: false
});
});
}
// Render the tags in the dialog box
private onRenderDialog = (tag: Tags, index: number): JSX.Element => {
return (
<div className={styles.tag} onClick={(e) => { e.stopPropagation(); this.collectTags(tag); }}>
<span># {tag.title} <i className="ms-Icon ms-Icon--CirclePlus"></i></span>
</div>
)
}
public render(): JSX.Element {
return <div className={styles.tagCloud}>
<div>
<h1>What are you interested in?</h1>
<p>We'll show you more stories from the topics you pick below</p>
</div>
<div>
<div className={styles.tagsContainer}>
{this.state.items.slice(0, 12).map((t, index) => this.renderTags(t, index))}
</div>
<div>
<a className={styles.allItemsLink} href="#" onClick={this._showDialog}>View all topcis</a>
</div>
<div>
{ this.state.hideSaveButton === false ? <DefaultButton
text="Done"
style={{ backgroundColor: '#ff0033', color: '#ffffff' }}
onClick={(e) =>{e.stopPropagation(); this.saveSettings()}}
/> : null}
</div>
</div>
<Dialog
hidden={this.state.hideDialog}
onDismiss={this._closeDialog}
containerClassName={'ms-dialogMainOverride ' + styles.textDialog}
modalProps={{
isBlocking: true,
}}>
<div className={styles.tagsDialogContainer}>
{this.state.allTags.map((t, index) => this.onRenderDialog(t, index))}
</div>
<DialogFooter>
<DefaultButton
style={{ backgroundColor: '#ff0033', color: '#ffffff' }}
onClick={this._closeDialog}
text="Done"
/>
</DialogFooter>
</Dialog>
</div>
}
private _showDialog = (): void => {
this.setState({ hideDialog: false });
this.props.provider.getAllTags().then((items) => {
this.setState({ allTags: items });
})
};
private _closeDialog = (): void => {
this.setState({ hideDialog: true });
}
}
Best regards
Americo
First of all you need to create separate method for event handling, for example onTagClick.
private renderTags(tag: Tags, index: number) {
return <div>
<div onClick={e => this.onTagClick(e, tag)}>
<p className={styles.tag}># {tag.title}
<i className="ms-Icon ms-Icon--CirclePlus"></i>
</p>
</div>
</div>
}
private onTagClick(tag: Tags, e: React.MouseEvent<HTMLElement>) {
e.stopPropagation();
this.collectTags(tag);
}
Another issue - you are mutating state directly, which not allowed in React.
// Here you creating the link to array named `selectedTags`.
let selectedTags: Tags[] = this.state.selectedTags;
// and here you mutating your state directly
selectedTags.push(newTag);
Just copy your array before adding new item or use spread operator.
private collectTags(newTag: Tags): any {
this.setState({
selectedTags: {
...this.state.selectedTags,
newTag
},
hideSaveButton: false
});
}
Also, don't forget to bind context to collectTags method in constructor.
constructor(props) {
super(props);
...some code if you have...
this.collectTags = this.collectTags.bind(this);
}
Hope it helped.
Related
I want to change the text of a specific button when I click on that button in React. But the issue is when I click the button the title will change for all buttons!
class Results extends Component {
constructor() {
super();
this.state = {
title: "Add to watchlist"
}
}
changeTitle = () => {
this.setState({ title: "Added" });
};
render() {
return (
<div className='results'>
{
this.props.movies.map((movie, index) => {
return (
<div className='card wrapper' key={index}>
<button className='watchListButton' onClick={this.changeTitle}>{this.state.title}</button>
</div>
)
})
}
</div>
)
}
}
You would need to come up with a mechanism to track added/removed titles per movie. For that, you would have to set your state properly. Example:
this.state = {
movies: [
{id: 1, title: 'Casino', added: false},
{id: 2, title: 'Goodfellas', added: false}
]
This way you can track what's added and what's not by passing the movie id to the function that marks movies as Added/Removed. I have put together this basic Sandbox for you to get you going in the right direction:
https://codesandbox.io/s/keen-moon-9dct9?file=/src/App.js
And here is the code for future reference:
import React, { Component } from "react";
import "./styles.css";
class App extends Component {
constructor() {
super();
this.state = {
movies: [
{ id: 1, title: "Casino", added: false },
{ id: 2, title: "Goodfellas", added: false }
]
};
}
changeTitle = (id) => {
this.setState(
this.state.movies.map((item) => {
if (item.id === id) item.added = !item.added;
return item;
})
);
};
render() {
const { movies } = this.state;
return (
<div className="results">
{movies.map((movie, index) => {
return (
<div className="card wrapper" key={index}>
{movie.title}
<button
className="watchListButton"
onClick={() => this.changeTitle(movie.id)}
>
{movie.added ? "Remove" : "Add"}
</button>
</div>
);
})}
</div>
);
}
}
export default App;
based on simple To-Do app, I'd like to understand how I can modify text of list item in place. List item contains 2 divs, first one holds todo's text and second one contains icons (delete, edit). I tried to conditionally render either first div or input inside the li, file ListItem.js, but that didn't work for me.
App.js
class App extends React.Component {
state = {
items: [],
currentValue: '',
clearValue: false
};
submitFormHandler = event => {
event.preventDefault();
if (this.state.currentValue === '') return;
const updatedItems = [...this.state.items];
if (
updatedItems.filter(udtItem => udtItem.value === this.state.currentValue)
.length === 0
) {
updatedItems.push({
id: uuidv4(),
value: this.state.currentValue,
completed: false
});
}
this.setState({ items: updatedItems, clearValue: true });
localStorage.setItem('todos', JSON.stringify(updatedItems));
};
changeInputHandler = event => {
this.setState({
currentValue: event.target.value,
clearValue: false
});
};
deleteItem = id => {
const updatedItems = [...this.state.items].filter(item => item.id !== id);
this.setState({ items: updatedItems });
localStorage.setItem('todos', JSON.stringify(updatedItems));
};
editItem = (event, id) => {
event.stopPropagation();
//do something here
};
deleteAll = () => {
this.setState({ items: [] });
localStorage.removeItem('todos');
};
componentDidMount() {
let todos = localStorage.getItem('todos');
if (todos) {
this.setState({ items: JSON.parse(todos) });
}
}
render() {
const itemList = this.state.items.map(item => (
<ListItem
key={item.id}
data={item}
deleted={this.deleteItem}
edited={this.editItem}
></ListItem>
));
return (
<div className="App">
<img src={trashIcon} alt="Delete" onClick={this.deleteAll} />
<header className="header">To-Do List</header>
<div className="items">
<ul>{itemList}</ul>
</div>
<form onSubmit={this.submitFormHandler}>
<Input
val={this.state.currentValue}
changed={e => this.changeInputHandler(e)}
clear={this.state.clearValue}
/>
</form>
</div>
);
}
}
export default App;
ListItem.js
class ListItem extends Component {
state = {
crossCheck: false,
hidden: true
};
toggleCrossCheck = () => {
const storageItems = JSON.parse(localStorage.getItem('todos'));
storageItems.forEach(item => {
if (item.id === this.props.data.id) {
item.completed = !item.completed;
this.setState({ crossCheck: item.completed });
}
});
localStorage.setItem('todos', JSON.stringify(storageItems));
};
componentDidMount() {
this.setState({ crossCheck: this.props.data.completed });
}
render() {
let classList = 'icon-container';
if (!this.state.hidden) classList = 'icon-container open';
return (
<li
className={this.state.crossCheck ? 'item cross-check' : 'item'}
onClick={this.toggleCrossCheck}
onMouseEnter={() => this.setState({ hidden: false })}
onMouseLeave={() => this.setState({ hidden: true })}
>
<div className="item-text">{this.props.data.value}</div>
<div className={classList}>
<Icon
iconType={trashIcon}
altText="Delete"
clicked={() => this.props.deleted(this.props.data.id)}
></Icon>
<Icon
iconType={editIcon}
altText="Edit"
clicked={event => this.props.edited(event, this.props.data.id)}
></Icon>
</div>
</li>
);
}
}
export default ListItem;
I used library react-sortable-hoc for drag and drop element, but the library documentation does not have any actions for delete items. I want to delete, drag and drop item when click on close button. Which method is right for removing elements by key from object?
React
const SortableItem = SortableElement(({ value }: { value: string }, onRemove: any) =>
<div className="dragItems" style={{ background: 'gray' }}>
<img src={value} alt="" />
<button className="dragCloseBtn" onClick={() => onRemove(any)} />
</div>
);
const SortableList = SortableContainer(({ items }: { items: string[] }) => {
return (
<div className="dragAndDrop">
{items.map((value, index) => (
<SortableItem key={'item-${index}'} index={index} value={value} />
))}
</div>
);
});
constructor(props: any) {
super(props);
this.state = {
items: [
{
"id": 0,
"link": "https://via.placeholder.com/150"
},
{
"id": 1,
"link": "https://via.placeholder.com/150"
}
],
};
}
public onSortEnd = ({ oldIndex, newIndex }: { oldIndex: number, newIndex: number }) => {
this.setState({
items: arrayMove(this.state.items, oldIndex, newIndex),
});
};
public onRemove(e: { target: { value: any; }; }) {
const array = [...this.state.items];
const index = array.indexOf(e.target.value)
if (index !== -1) {
array.splice(index, 1);
this.setState({items: array});
}
}
<SortableList items={this.state.items}
onSortEnd={this.onSortEnd}
lockAxis="xy"
axis="xy" />
UPDATED:
Hi there, I figured out what went wrong and made a successful remove event on your application.
Everything is illustrated with comments at this codesandbox.
=========
I modified this one, it should do the required using Array's filter method.
public onRemove(e: { target: { value: any; }; }) {
let array = [...this.state.items];
const intId = parseInt(e.target.value, 10);
array = array.filter(item => item.id !== intId);
this.setState({items: array});
}
So there were few problems in your code! You seemed to be confuse how react works with passing down props. You have to pass down the method required for remove. And you should bind it inside the class that you will be calling it.
onRemove should be bound to current context
onRemove should be passed down across the component tree
Check my //[NOTE]====> comments for additional explanation
Working code sandbox is here
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
arrayMove,
SortableContainer,
SortableElement
} from "react-sortable-hoc";
//[NOTE]====>value contains the relevent object containing the callback. Onclick call it with the relevant id
const SortableItem = SortableElement(
({ value }: { value: any }, onRemove: any) => (
<div className="dragItems" style={{ background: "gray", margin: "20px" }}>
<img src={value.link} alt="" />
<button className="dragCloseBtn" onClick={() => value.onRemove(value.id)}>
{" "}
X{" "}
</button>
</div>
)
);
const SortableList = SortableContainer(({ items }: { items: string[] }) => {
return (
<div className="dragAndDrop">
{items.map((value, index) => (
<SortableItem key={`item-${index}`} index={index} value={value} />
))}
</div>
);
});
class SortableComponent extends React.Component<{}, { items: string[] }> {
constructor(props: {}) {
super(props);
//[NOTE]====>Send the callback on each element bound to the current context
//This is like telling the function from where exactly the function will be called
this.state = {
items: [
{
id: 0,
link: "https://via.placeholder.com/150",
onRemove: this.onRemove.bind(this)
},
{
id: 1,
link: "https://via.placeholder.com/150",
onRemove: this.onRemove.bind(this)
}
]
};
}
public render() {
return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />;
}
public onSortEnd = ({
oldIndex,
newIndex
}: {
oldIndex: number;
newIndex: number;
}) => {
this.setState({
items: arrayMove(this.state.items, oldIndex, newIndex)
});
};
//[NOTE]====>Use the id to filter out and set the new set of items
public onRemove(id) {
console.log(id);
let array = [...this.state.items];
const intId = parseInt(id, 10);
array = array.filter((item: any) => item.id !== intId);
this.setState({ items: array });
}
}
ReactDOM.render(<SortableComponent />, document.getElementById("root"));
I have a play/pause button for every video.
When I click on the play button, the last video is always played, and the icon changes on all videos. I try to do that with refs and play() method but every time, whatever video the user selects just the last video is played. Every click event play the last one.
Also, the code for full screen does not work.
This is my code:
class Video extends React.Component {
constructor(props) {
super(props);
this.state = {
playing: false,
videoList: [
{
src: 'https://clips.vorwaerts-gmbh.de/VfE_html5.mp4',
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
}
]
}
}
onPlayPauseClick = (index) => (event) => {
this.setState({
playing: !this.state.playing
});
this.state.playing ? this.video.pause() : this.video.play();
}
// onFullScreenClick = (video) => {
// this.setState({ video: video })
// if (video.requestFullscreen) {
// video.requestFullscreen();
// } else if (video.webkitRequestFullscreen) {
// video.webkitRequestFullscreen();
// } else if (video.mozRequestFullscreen) {
// video.mozRequestFullscreen();
// } else if (video.msRequestFullscreen) {
// video.msRequestFullscreen();
// }
// }
renderList = () => {
const { playing } = this.state;
return this.state.videoList.map((item, index) => {
return (
<li key={`item_${index}`}>
<video ref={(video) => { this.video = video; }} src={item.src}></video>
<img
src={playing ? "https://icon2.kisspng.com/20180419/pyq/kisspng-computer-icons-arrow-triangle-play-icon-5ad83452103159.1624767815241186100663.jpg" : "https://cdn2.iconfinder.com/data/icons/flat-and-simple-pack-2/512/1_Control_pause-512.png"}
className="play"
onClick={this.onPlayPauseClick(index)}
/>
<img src="https://cdn3.iconfinder.com/data/icons/google-material-design-icons/48/ic_fullscreen_exit_48px-512.png" className="full" />
</li>
)
});
}
render() {
return (
<div>
<ul>
{this.renderList()}
</ul>
</div>
);
}
}
class Buttons extends React.Component {
render() {
return (
<div>
<Video />
</div>
);
}
}
ReactDOM.render(<Video />, document.getElementById('app'));
It's happened because you saved the last video item in this.video, after iterating through videoList array elements . Try to save ref in this['video_'+index]=video instead of this.video=video, and start to play with code this['video_'+index].play()
Hey I think you have your ref messed up, you can create a new array of ref and use it with the index
constructor () {
this.ref = [];
}
and in your return do something like this
return this.state.videoList.map((item, index) => {
return (
<li key={`item_${index}`}>
<video ref={(video) => { this.ref.push(video) }} src={item.src}></video>
<img
src={playing ? "https://icon2.kisspng.com/20180419/pyq/kisspng-computer-icons-arrow-triangle-play-icon-5ad83452103159.1624767815241186100663.jpg" : "https://cdn2.iconfinder.com/data/icons/flat-and-simple-pack-2/512/1_Control_pause-512.png"}
className="play"
onClick={this.onPlayPauseClick(index)}
/>
<img src="https://cdn3.iconfinder.com/data/icons/google-material-design-icons/48/ic_fullscreen_exit_48px-512.png" className="full" />
</li>
)
});
and then you can call your ref inside the play pause method
onPlayPauseClick = (index) => (event) => {
this.setState({
playing: !this.state.playing
});
this.state.playing ? this.ref[index].pause() : this.ref[index].play();
}
For fullscreen I can suggest you don't try to over complicate the things, there is an awesome library for the player you can go with it.
https://www.npmjs.com/package/react-player
Full functioning code for your question.
import React from "react";
class Video extends React.Component {
constructor(props) {
super(props);
this.video = [];
this.state = {
playing: [false, false, false, false],
videoList: [
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
},
{
src: "https://clips.vorwaerts-gmbh.de/VfE_html5.mp4",
type: "video/mp4"
}
]
};
}
onPlayPauseClick = index => event => {
this.setState(state => {
state.playing = !state.playing;
state.playing ? this.video[index].play() : this.video[index].pause();
return state.playing[index];
});
};
onFullScreenClick = index => event => {
let video = this.video[index];
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen();
} else if (video.mozRequestFullscreen) {
video.mozRequestFullscreen();
} else if (video.msRequestFullscreen) {
video.msRequestFullscreen();
}
};
renderList = () => {
const { playing } = this.state;
return this.state.videoList.map((item, index) => {
return (
<li key={`item_${index}`}>
<video
ref={video => {
this.video[index] = video;
}}
src={item.src}
/>
<img
src={
playing
? "https://icon2.kisspng.com/20180419/pyq/kisspng-computer-icons-arrow-triangle-play-icon-5ad83452103159.1624767815241186100663.jpg"
: "https://cdn2.iconfinder.com/data/icons/flat-and-simple-pack-2/512/1_Control_pause-512.png"
}
className="play"
onClick={this.onPlayPauseClick(index)}
/>
<img
src="https://cdn3.iconfinder.com/data/icons/google-material-design-icons/48/ic_fullscreen_exit_48px-512.png"
className="full"
onClick={this.onFullScreenClick(index)}
/>
</li>
);
});
};
render() {
return (
<div>
<ul>{this.renderList()}</ul>
</div>
);
}
}
export default Video;
Im use react-player, where option "controls" - Set to true or false to display native player controls. look at the "react-player", it has everything you need
<ReactPlayer url={'url/to/video'} className={classes.styleView} controls/>
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