Parent state passed as props not updated when rendered in .map function - javascript

In the TableAndInfo Component, each row's parent element is rendered by the renderEls function and the content is returned by the renderSection function. This passes in the content in the sections property as a parameter, as well as the class of the parent container. Passing the props value of date, time, and current in the sections array results in a successful initial render, but they do not continue updating when the state changes. I have inspected the code with the React Developer Tools and I see that the state is being updated by the functions defined in the App function and other components. How do I ensure that the grandchildren elements are re-rendered when the state is updated? Sorry if this doesn't make sense, I was having trouble trying to explain the problem. Thanks in advance!
function App() {
var [component, updateView] = useState('ServerFunctions');
var updateDateAndTime = function(formatDate) {
setInterval(function() {
if (document.getElementsByClassName('date')[0] && document.getElementsByClassName('time')[0]) {
updateDate(formatDate('date'));
updateTime(formatDate('time'));
}
}, 1000);
};
useEffect(() => {
updateDateAndTime(formatDate);
});
var [date, updateDate] = useState(formatDate('date'));
var [time, updateTime] = useState(formatDate('time'));
switch(component) {
case 'Welcome':
return (<Welcome updateView={updateView} date={date} time={time} backspacePinpad={backspacePinpad} />);
case 'ServerFunctions':
return (<ServerFunctions updateView={updateView} date={date} time={time} />);
default:
return null;
}
}
class TablesAndInfo extends React.Component {
sections = [[['info-row pct-space-b', 'flex between full-h'], {
1: ['Menu', 'button', 'gray white-f clickable roundish quarter-w label clickable'],
2: [this.props.current, 'div', 'f-override white-b small left three-quarter-w no-txt-overflow'],
}], [['info-table full-h', 'flex full-h'], {
1: ['Another Round', 'button', 'info-button blue white-f clickable'],
2: ['Select All', 'button', 'info-button gray white-f clickable'],
3: ['Name Check', 'button', 'info-button yellow clickable'],
}], [['tables-section full-h', 'tables-section full-h white-b'], {
}], [['new-table-b full-h', 'new-table-b med single round label full-h full-w'], {
1: ['New Table', 'button', 'blue white-f med single clickable round label clickable full-h full-w']
}]];
renderEls(num, classes) {
return (
<div className={classes}>
{this.sections[num].map((child, key) => {
if (typeof child === 'object' && !(child instanceof Array)) {
return (
<div className={this.sections[num][0][0]}>{this.renderSection(child, this.sections[num][0][1], key)}</div>
)
} else {
return null;
}
})}
</div>
)
}
renderSection(obj, parentClass) {
return (
<div className={parentClass}>
{Object.keys(obj).map((key, i) => {
if (obj[key][1] === 'button') {
return (
<button key={i} className={"flex center " + obj[key][2]}>{obj[key][0]}</button>
)
} else {
return (
<div key={i} className={"flex center " + obj[key][2]}>{obj[key][0]}</div>
)
}
})}
</div>
)
}
render() {
return (
<div className="tables space-r">
<div className="info tables-section">
{this.renderEls(0, 'info-table info-r')}
{this.renderEls(1, 'info-table info-b')}
</div>
{this.renderEls(2, 'table-view tables-section full-h pct-space-b')}
{this.renderEls(3, 'new-table')}
</div>
)
}
class ServerFunctions extends React.Component {
return (
<div className="App ServerFunctions">
<Header signOff={this.signOff} renderBttnRow={this.renderBttnRow} />
<div className="container order-control flex space-b">
<SelectedItems />
<TablesAndInfo current={this.state.current} date={this.props.date} time={this.props.time} />
<Functions current={this.state.current} />
</div>
<Footer current={this.state.current} renderBttnRow={this.renderBttnRow} />
</div>
)
}
}

Ended up solving this! Here's what I added in the TablesAndInfo Component:
constructor(props) {
super(props);
this.state = {current: this.props.current, date: this.props.date, time: this.props.time}
}
shouldComponentUpdate(nextProps) {
if ((nextProps.current !== this.state.current) || (nextProps.date !== this.state.date) || (nextProps.time !== this.state.time)) {
this.setState({current: nextProps.current});
this.setState({date: nextProps.date});
this.setState({time: nextProps.time});
}
return true;
}
componentDidUpdate() {
this.sections[0][1][2][0] = this.state.current;
this.sections[0][2][1][0] = this.state.time;
this.sections[0][2][2][0] = this.state.date;
}

Related

ReactJS rendering issue with edited array

Why does ReactJS remove the last element when the array is different after removing the middle element when using array.splice?
This is my code. I am using React-Redux.
const reducerNotesAndLogin = (state = initialState, action) => {
var tableNotes = "notities";
var tableCategories = "categories";
switch(action.type){
case "CATEGORY_REMOVE":
// Remove the category
var newCategories = state.categories;
console.log("state.categories", state.categories);
console.log("before: ", {newCategories});
var index = 0;
for(var i = 0; i < newCategories.length; i++){
if(newCategories[i].id === action.payload.categoryId){
newCategories.splice(i, 1);
index = i;
i--;
}
}
console.log("after: ", {newCategories});
state = {
...state,
categories: newCategories
}
break;
default:
break;
}
return state;
}
export default reducerNotesAndLogin;
Output below (I deleted the middle element. My web app always removes the last element of the categories (but not from the array).
Step 1: Initial state
Step 2: Remove middle item, expecting the middle item to be removed.
Step 3: Confusion
Why is the array correct, but the view incorrect? I am updating the state.categories correctly right?
This is my render code (as is - without filtering away any other code that mihgt be important)
CategoriesBody:
import React from 'react';
import { connect } from 'react-redux';
import CategoryItem from './CategoryItem';
import Button from './../../Button';
import store from '../../../redux/store-index';
class CategoriesBody extends React.Component {
render(){
return (
<div>
<ul className="list--notes">
{this.props.categories.map((category) => {
if(category.id === undefined){ // No categories
return <li>No categories</li>
} else {
return (
<div>
<CategoryItem category={category} />
<div className="mb-small hidden-sm hidden-md hidden-lg"> </div>
</div>
);
}
})}
</ul>
</div>
);
}
}
function mapStateToProps(state){
return {
categories: state.reducerNotesAndLogin.categories,
categoriesLength: state.reducerNotesAndLogin.categories.length
};
}
export default connect(mapStateToProps)(CategoriesBody);
CategoriesItem.js:
import React from 'react';
import store from './../../../redux/store-index';
import Button from './../../Button';
class CategoryItem extends React.Component {
constructor(props){
super();
this.state = {
edit: false,
categoryName: props.category.categoryName,
categoryColor: props.category.categoryColor
}
this.onClickEdit = this.onClickEdit.bind(this);
this.onChangeCategoryColor = this.onChangeCategoryColor.bind(this);
this.onChangeInputCategoryName = this.onChangeInputCategoryName.bind(this);
this.onClickEditSave = this.onClickEditSave.bind(this);
this.onClickEditCancel = this.onClickEditCancel.bind(this);
}
removeCategory(id, name){
console.log("nsvbsvbfjvbdjhbvv");
store.dispatch({ type: "CATEGORY_REMOVE", payload: {
categoryId: id
}});
// store.dispatch({type: "NOTIFY", payload: {
// type: 'success',
// message: 'Category "' + name + '" removed!'
// }});
}
onClickEdit(){
this.setState({
edit: true
});
}
onChangeCategoryColor(e){
this.setState({
categoryColor: e.target.value
});
}
onChangeInputCategoryName(e){
this.setState({
categoryName: e.target.value
});
}
onClickEditSave(){
this.setState({
edit: false,
categoryName: this.state.categoryName,
categoryColor: this.state.categoryColor
});
store.dispatch({type: "CATEGORY_EDIT", payload: {
categoryId: this.props.category.id,
categoryName: this.state.categoryName,
categoryColor: this.state.categoryColor
}});
store.dispatch({type: "NOTIFY", payload: {
type: "success",
message: "Category saved!"
}});
}
onClickEditCancel(){
this.setState({
edit: false,
categoryName: this.props.category.categoryName,
categoryColor: this.props.category.categoryColor
});
}
render(){
return (
<li key={this.props.category.id} className={this.state.edit === true ? "mt mb" : "flex-justify-between flex-align-center"}>
<div className={this.state.edit === true ? "d-none" : ""}>
<div className="input--color" style={{
backgroundColor: this.state.categoryColor
}}> </div>
{this.state.categoryName}
</div>
{/* Mobile */}
<div className={this.state.edit === true ? "d-none" : "hidden-sm hidden-md hidden-lg"}>
<Button onClick={() => this.onClickEdit()} buttonType="primary">Edit</Button>
<div className="mt-small"> </div>
<Button onClick={() => this.removeCategory(this.props.category.id, this.props.category.categoryName)} type="primary">Remove</Button>
</div>
{/* Tablet and desktop */}
<div className={this.state.edit === true ? "d-none" : "hidden-xs"}>
<div style={{float:'left',}}><Button onClick={() => this.onClickEdit()} buttonType="primary">Edit</Button></div>
<div style={{float:'left',marginLeft:'15px'}}><Button onClick={() => this.removeCategory(this.props.category.id, this.props.category.categoryName)} type="primary">Remove</Button></div>
</div>
{/* EDITING STATE */}
<div className={this.state.edit === true ? "" : "d-none"}>
<div className="row">
<div className="col-xs-12">
<input onChange={this.onChangeCategoryColor} className="input--wide" type="color" value={this.state.categoryColor}
style={{backgroundColor: this.state.categoryColor, height: '30px'}}
/>
<input onChange={this.onChangeInputCategoryName} className="input--wide" type="text" value={this.state.categoryName} />
</div>
</div>
<div className="row mt">
<div className="col-xs-12">
<Button buttonType="primary" onClick={() => this.onClickEditSave()}>Save</Button>
</div>
</div>
<div className="row mt-small">
<div className="col-xs-12">
<Button buttonType="secondary" onClick={() => this.onClickEditCancel()}>Cancel</Button>
</div>
</div>
</div>
</li>
)
}
}
export default CategoryItem;
I think it has something to do with the rendering. Because the arrays are correct when I console.log them. Only the view is different...
Do not modify the state in reducer directly. Create a copy of state value and then modify it.
Change:
var newCategories = state.categories;
To:
var newCategories = [...state.categories];
You should not modify the same array while looping through it.
for (var i = 0; i < newCategories.length; i++) {
if (newCategories[i].id === action.payload.categoryId) {
newCategories.splice(i, 1);
index = i;
i--;
}
}
I got the answer after looking through it with a friend of mine. The solution is pretty simple...
Lesson 101: Make sure that you have a unique "key" property when looping through an array in your UI.
The solution is to add this to my code:
<div key={category.id}>
{this.props.categories.map....
...
</div>

ReactJS: Reset-Render Child Component on Parent state change

I have a strange - at least for me :-) - issue with my Components.
I have a map() function generating a list of Child elements. When I change the filter and the list repopulates the state of the children remain as it was. For example, if the second Alumni Child Component has state {height:auto} the new second Allumni Child has again {height: auto}.
I find it really odd because this is not the same element, it's a new element corresponding to another person, with new content passed through props.
Long story short how do I force my new Child elements to have initial state {height: 0}?
There is a lot of details hidden but the core of my Parent App is as follows:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
filterName: "",
filterInitial: "Α",
....
filteredGraduates:[],
loaderVisible:true
};
this.updateInitial = this.updateInitial.bind(this)
...
}
componentDidMount(){
...
}
updateInitial(letter) {
if (letter==='*'){
this.setState({
filterInitial: "*",
filteredGraduates : [...graduates]
})
}else{
this.setState({
filterInitial: letter,
filteredGraduates : graduates.filter( (graduate) => graduate.Surname.charAt(0)===letter )
})
}
console.log('this is the letter: ',letter);
}
render() {
return (
<div className="app">
<div className="filters">
<div className="name-pagination">
<span
onClick={ () => this.updateInitial('*')}
className={'*'==this.state.filterInitial? 'active': ''}
>Α - Ω
</span>
<hr/>
{letters.map( (letter) => {
return(
<span
onClick={ () => this.updateInitial(letter)}
className={letter==this.state.filterInitial? 'active': ''}
>{letter}</span>
)
}
)}
</div>
</div>
</div>
{this.state.loaderVisible && <Loader /> }
{!this.state.loaderVisible && <div className="graduates-wrapper">
{this.state.filteredGraduates
.sort( (x,y) => x.Surname.localeCompare(y.Surname) )
.map( (graduate) => {
return(
<div>
<Allumni
key={graduate.id}
.... a lot of props ...
/>
</div>
)
})
}
</div>}
</div>
);
}
}
and my Child is:
class Allumni extends React.Component {
constructor(props) {
super(props);
this.state = {
height:0
};
this.updateHeight = this.updateHeight.bind(this)
}
updateHeight() {
this.setState({
height: this.state.height === 0 ? 'auto' : 0,
});
};
render() {
const {
name,
surName,
.......
} = this.props
return (
<div className="allumni-wrapper">
<div className="allumni-main-info">
<span className="allumni-surname">{surName}</span><br/><span className="allumni-name">{name}</span>
</div>
<div className="allumni-extra">
<span className="allumni-year">{yearOf}</span><br/>
<span className="allumni-job">{job}</span> / <span className="allumni-home-city">{homeCity}</span>
</div>
<div className="allumni-details">
<AnimateHeight
duration={ 500 }
height={ this.state.height }
>
<p><span className="attribute-name">... {fatherName}</p>
<p><span className="attribute-name">...{studies}</p>
....
</AnimateHeight>
</div>
<div className="allumni-actions" onClick={this.updateHeight}>
<AccountCardDetailsOutlineIcon size={30}/>
<span className={'actions-toggle ' + (this.state.height >= 0 ? '' : 'rotated') }><ChevronDownIcon/></span>
</div>
</div>
);
}
}
export default Allumni
thank you

ReactJS: how to map JSON elements sequentially and show the hidden div on click

I'm trying to load items from JSON and toggle a dropdown div with description on click. While I can display elements sequentially (ex: loc1 & desc1, loc2 & desc2) on static divs I'm having trouble finding out how to render it properly when the second part (desc) is hidden and only shows when the loc div is clicked.
What would be the best way to map the result so it doesn't show as loc1 & loc2, desc1 & desc2 but as loc1 & desc1, loc2 & desc2?
Code:
var places = {
library: {
location: [
{
loc_name: "library1",
"desc": "desc1 : Modern and spacious building"
},
{
loc_name: "library2",
"desc": "desc2 : A cosy small building"
}
]
}
};
function contentClass(isShow) {
if (isShow) {
return "content";
}
return "content invisible";
}
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isShow: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(function (prevState) {
return { isShow: !prevState.isShow };
});
}
render() {
const libraries_desc = places.library.location.map((libr) =>
<div>
<p>{libr.desc}</p>
</div>
);
const lib_names = places.library.location.map((libr) =>
<div>
<p>{libr.loc_name}</p>
</div>
);
return (
<div>
<div className='control' onClick={this.handleClick}>
<h4>{lib_names}</h4>
<div className={contentClass(this.state.isShow)}>{libraries_desc}</div>
</div>
</div>
);
}
}
render((
<Toggle />
), document.getElementById('root'));
Current result:
library1
library2
desc1 : Modern and spacious building
desc 2 : A cosy small building
Desired Result:
library1
desc1 : Modern and spacious building (hidden but shown when clicked)
library2
desc 2 : A cosy small building (hidden but shown when clicked)
Codesandbox
I might try extracting a location into a separate component. By extracting it, each location is responsible for knowing its state. In your case, that means its visibility (controlled by this.state.isShow).
Here's how you could do it:
import React from 'react';
import { render } from 'react-dom';
var places = {
library: {
location: [
{
loc_name: "library1",
"desc": "Modern and spacious building"
},
{
loc_name: "library2",
"desc": "A cosy small building"
}
]
}
};
class Location extends React.Component {
constructor(props) {
super(props);
this.state = { isShow: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(function (prevState) {
return { isShow: !prevState.isShow };
});
}
contentClass(isShow) {
if (isShow) {
return "content";
}
return "content invisible";
}
render() {
return (
<div className='control' onClick={this.handleClick}>
<h4>{this.props.desc}</h4>
<div className={this.contentClass(this.state.isShow)}>{this.props.loc_name}</div>
</div>
)
}
}
class Toggle extends React.Component {
constructor(props) {
super(props);
}
render() {
const locations = places.library.location.map(location => {
return <Location {...location} />
})
return (
<div>
{locations}
</div>
);
}
}
render((
<Toggle />
), document.getElementById('root'));
Your Toggle Component should be like this.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: false,
id: -1, // initial value
};
}
handleClick = (id) => {
this.setState({
isShow: !this.state.isShow,
id: id
});
}
render() {
const { location } = places.library;
const { isShow, id } = this.state;
return (
<div className="control">
{location.map((libr, index) => (
<div key={index} onClick={() => { this.handleClick(index) }}>
<p>{libr.loc_name}</p>
{(isShow && (id === index)) && <p>{libr.desc}</p>}
</div>
))}
</div>
);
}
}
So when you click on the div element. A click event will be triggered called handleClick which will pass the index as a param to the function. which will set isShow to false or truth and vice versa along with the current element you want to show which will be selected through this.state.id. So everytime isShow is true and this.state.id matched index element of the array. Your description will show otherwise it will be hidden as you want.
So your desired result will be something like this.
library1
desc1 : Modern and spacious building (hidden but shown when clicked)
library2
desc 2 : A cosy small building (hidden but shown when clicked)

Reactjs - Building form from data set, FormElement not returning to the render function

I am dynamically building a form based on the state build in the constructor. I am having success building the outer html but the inner form html is not rendering. cAN SOMEONE POINT OUT WHAT i AM DOING WRONG HERE?
class Forms extends Component {
constructor(props) {
super(props);
this.state = {
enrollment: {
class: "form-style",
fieldsets: [{
id: "1",
title: "Company Enrollment Form",
formElements: [{
label: "Company Name:",
element: "input",
type: "text",
class: "",
name: "cName",
placeholder: "Your Company's Name *",
required: true,
disabled: false
}, {
label: "Company Type:",
element: "select",
type: "populateDDL",
class: "",
name: "sltCompanyType",
placeholder: "",
required: true,
disabled: false
}]
}]
}
}
}
render() {
let Content = null;
if (this.props.type === "enrollment") {
Content = <EnrollmentForm state={this.state.enrollment} />
} else if (this.props.type === "contact") {
Content = <ContactUsForm />
} else {
Content = <fourOhFour />
}
return (
<div className="container formContent">
{Content}
</div>
);
}
};
function EnrollmentForm(form) {
function renderFieldsets(fieldsets) {
if (fieldsets.length > 0) {
return fieldsets.map((fieldset, index) => (
<Fieldset key={index} set={fieldset} />
));
}
else return [];
}
function renderFormElements(formElements) {
if (formElements.length > 0) {
return formElements.map((formElement, i) => (
<FormElement key={i} set={formElement} />
));
}
else return [];
}
const FormElement = (props, index) => {
console.log(props);
/* ^^^ NOT APPEARING/LOGGING IN THE CONSOLE ^^^ */
if (props.tag === "input") {
return (
<input key={index} name={props.name} />
);
}else if (props.tag === "select") {
return (
<select key={index} />
);
}
};
const Fieldset = (props, index) => {
const elements = renderFormElements(props.set.formElements);
return (
<fieldset key={index}>
<legend>
<span className="number fa fa-address-card"></span>
{props.set.title}
</legend>
</fieldset>
);
};
const fieldsets = renderFieldsets(form.state.fieldsets);
return (
<form className={form.state.class}>
{fieldsets}
</form>
);
}
The FormElement variable is not returning the html... I need to return a different type of html element based on what the tag is in the data model. In the code I have successfully created the outer fieldset but when I go to insert the html elements inside the fieldset, it doesn't do anything. I put a console.log in the code block but apparently even when I try to use the "FormElement" the code isn't firing ...
You have bugs in your code.
Your FormElement should look like
const FormElement = (props, index) => {
console.log(props);
/* ^^^ NOT APPEARING/LOGGING IN THE CONSOLE ^^^ */
if (props.set.element === "input") {//changed from props.tags-- 1
return (
<input key={index} name={props.name} />
);
}else if (props.set.element === "select") {//changed from props.tags --1
return (
<select key={index} />
);
}
return <div>Something which is not select or input</div>; //added a fallback return. --1
};
The bugs that were fixed above are:
(1) props.tags changed to props.set.element. There was no tags component in the props. So none of the if blocks were being rendered and this led to the component not returning anything. This led to an error that said
FormElement(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
This was resolved by adding the fallback return statement (2).
Your FieldSets should look like
const Fieldset = (props, index) => {
const elements = renderFormElements(props.set.formElements);
return (
<fieldset key={index}>
<legend>
<span className="number fa fa-address-card"></span>
{props.set.title}
</legend>
<div>{elements}</div> // consumed the elements that was created in renderFormElements.
</fieldset>
);
};
The elements variable was never used in render, which led to no FormElements showing up. That was the only error fixed in the above code.
I would suggest cleaning up your code by
Converting EnrollmentForm to a class.
Moving FieldSet and FormElement to seperate classes or at least funtional components
That would make the logic a lot easier to debug in future.

ReactJS - Target random element

I have some problems understanding how you interact with element in React after rendering. I currently got this fiddle: https://jsfiddle.net/y7dh3vh5/
var items = ["Afghanistan","Albania","Algeria","Andorra","Angola"....
var RepeatModule = React.createClass({
getDefaultProps: function() {
return { items: [] }
},
render: function() {
var listItems = this.props.items.map(function(item, i) {
return (
<div className="item" key={i}>
<p>{item}</p>
</div>
);
});
return (
<div>
{listItems}
</div>
);
}});ReactDOM.render(<RepeatModule items={items} />, document.getElementById('itemList'));
And I'm looking for a way to highlight a random country when I press the "Highlight random country"-button. Is there an easy way to implement this?
Thanks in advance.
Add state to save highlightedIndex:
getInitialState () {
return {
highlightedIndex: -1
}
},
Add method for button
setNewTarget: function() {
var l = this.props.items.length - 1;
this.setState({
highlightedIndex: this.randomInteger(0, l)
})
},
Put button into return render
return (
<div>
<button onClick={this.setNewTarget}>
Highlight random country
</button>
{listItems}
</div>
);
Live example: https://jsfiddle.net/ufmagg4o/
Just keep your index element in state and compare it in map method. I prefere es6 so i hope you will understand
class Example extends React.Component {
constructor(){
this.state = {
items: ['hello', 'world', 'random', 'highlight'],
index: null
}
this.click = this.click.bind(this);
}
click(){
const items = this.state.items;
const index = Math.floor(Math.random()*items.length);
this.setState({index: index})
}
render(){
const list = this.state.items.map((item,index)=>{
return <p key={index} className={this.state.index === index ? 'item': null}>
{item}
</p>
})
return <div>
<button onClick={this.click}>Click me</button>
{list}
</div>
}
}
React.render(<Example />, document.getElementById('container'));
fiddle example
Thanks!
The key is to keep that button inside React. Don't try to manipulate React components from outside React.
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>
<div id="itemList">
</div>
.highlighted {
color: white;
background-color: tomato;
}
var items = [
"Afghanistan",
"Albania",
"Algeria",
"Andorra",
"Angola"
]; // etc...
var RepeatModule = React.createClass({
getDefaultProps: function() {
return { items: [] }
},
getInitialState() {
return {highlighted: null};
},
onClickButton() {
this.setState({
highlighted: (Math.random() * this.props.items.length)|0
});
},
render: function() {
var _this = this;
var listItems = this.props.items.map(function(item, i) {
return (
<div className="item" key={i}>
<p className={i == _this.state.highlighted ? 'highlighted' : null}>
{item}
</p>
</div>
);
});
return (
<div>
<button onClick={this.onClickButton}>
Highlight random country
</button>
<div>
{listItems}
</div>
</div>
);
}
});
ReactDOM.render(<RepeatModule items={items} />, document.getElementById('itemList'));
jsfiddle
ES2015 version:
const items = [
"Afghanistan",
"Albania",
"Algeria",
"Andorra",
"Angola"
]; // etc...
class RepeatModule extends React.Component {
static propTypes = {items: React.PropTypes.arrayOf(React.PropTypes.string)};
static defaultProps = {items: []};
state = { highlighted: null };
onClickButton = () => {
this.setState({
highlighted: (Math.random() * this.props.items.length)|0
});
};
render() {
const listItems = this.props.items.map((item, i) => (
<div className="item" key={i}>
<p className={i == this.state.highlighted ? 'highlighted' : null}>
{item}
</p>
</div>
));
return (
<div>
<button onClick={this.onClickButton}>
Highlight random country
</button>
<div>
{listItems}
</div>
</div>
);
}
});
ReactDOM.render(<RepeatModule items={items} />, document.getElementById('itemList'));

Categories