Many times in UI development we get request from client/user to highlighted item from a list once clicked upon. It can be a navbar, a list of videos or anything else. Now we don’t just have to highlight an item, but also to unhighlight it if some other item is clicked. Don’t confuse it with hover state, which can be easily done by CSS. But to do this is react is a task as we have to play with state, props, callbacks.
Let’s refactor the youtube player which we created in the the Youtube player with react series. We will now clone the repo and do a npm install.
Clone the repo
Now let’s open the project in our code editor. While creating this app in earlier series i have explained how it works. For the highlighting thing to work, we have make changes in video_list.js and video_list_item.js I have learnt the way to highlight from this stackoverflow post and since then applied to many of my work related projects.
Now the main logic is that, we have to manage the state from the parent(video_list.js) and if the state is true, we have to change the color of that item in children(video_list_item.js). The children have the onClick event and tell the parent that it was clicked, so make it active.
Let’s code and it will be more clear. First we will make the changes in our parent(video_list.js). It is currently like below. A function based component.
current video_list.js
We will change it to a class based component, as we need it to have state and also add a callback function to change the state.
updated video_list.js
The main changes are highlighted in yellow. We changed to class based component, added a state variable activeIndex. Also created a handleChange(), which will be changed via a callback function.
We are also passing three new props to our child component VideoListItem — One a callback , second the current index and third an active flag, which will be either true or false.
Let’s update the children(video_list_item.js) now and then we will go through the whole cycle once.
Our current video_list_item.js is as below.
current video_list_item.js
We will change it to contain some inline styles and also handle the new props we created in video_list.js
updated video_list_item.js
The changes are highlighted in yellow. First did some ES6 destructuring to take those props from video_list.js in variable. Then created an object styles for inline style, which we will apply to the selected component.
In the li now we have a second selectedByUser callback attached to the onClick handler. It takes the current Index passed by parent component and pass it back once user clicks on it. We also have the styles attached here, which are shown if active flag is set as true.
Now, lets understand the complete cycle once. During the first render() in video_list.js we have the active as null because activeIndex was not changed and set to let active = this.state.activeIndex; Now the VideoListItem will have the active as false for all the video list item because active={index === active}. index will be from 0 to 4 while going through the map loop and active is null , so 0 === null and it will be false.
Now in video_list_item.js we initially have style as inactive because active props from parent is false for all five video items. Once a user clicks on one of them, we send the index back to the parent by the callback function selectedByUser(currIndex)
. Now this will trigger the handleChange()
in video_list.js
by selectedByUser={selectedIndex => this.handleChange(selectedIndex)}
The function changes the activeIndex to the selected index(say 4) by -
handleChange(sldIndex) {
this.setState({
activeIndex: sldIndex
});
}
Now, as we know if a state is changed in react it runs the render() again, which will trigger all children components also.
Now, this time active will be a number in below statement. Let say 4(assume the fifth video was clicked) let active = this.state.activeIndex;//let active = 4
Now, we will go through our map five time. First 4 times(ie 0 to 3), we will have active as false
active={index === active}
// 0 === 4 no, so false
// 1 === 4 no, so false
// 2 === 4 no, so false
// 3 === 4 no, so false
> But, bingo the when we go through the map 5th time ie for 4
active={index === active}
// 4=== 4 yes, so true
So, when these five videos goes to video_list_item.js , only one of them have active set as true and other four as false.
And this true one gets the style
isactive: {
border: ‘4px solid #008dc8’,
background: ‘#eee’
}
because of -
style={active ? styles.isactive : styles.inactive}
And now we get this.
The new highlighting app
You can find the repo here.