Skip to content

Commit dd4c42e

Browse files
Adding an example of using ShouldComponentUpdate
1 parent 608e646 commit dd4c42e

File tree

6 files changed

+94
-51
lines changed

6 files changed

+94
-51
lines changed

lib/components/App.js

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,18 @@ class App extends React.Component {
2727

2828
state = this.props.store.getState();
2929

30-
onStoreChange=()=>{
30+
onStoreChange = () => {
3131
this.setState(this.props.store.getState);
3232
}
3333

34-
componentDidMount(){
34+
componentDidMount() {
3535
//we need to update the component state so the app component state is in sync to the store state
36-
if(this.subsciptionId) {
37-
this.subsciptionId = this.props.store.subscribe(this.onStoreChange);
38-
}
36+
this.subsciptionId = this.props.store.subscribe(this.onStoreChange);
3937
this.props.store.startClock();
4038
}
4139

42-
componentWillUnmount(){
40+
componentWillUnmount() {
4341
this.props.store.unsubscribe(this.subscriptionId);
44-
this.subscriptionId = null;
4542
}
4643

4744
//In react we cannot return two elements unless
@@ -72,22 +69,22 @@ class App extends React.Component {
7269
// or manage subscriptions in the same object
7370

7471
render() {
75-
let { articles , searchTerm}=this.state;
72+
let {articles, searchTerm} = this.state;
7673
//making the search case insensitive
7774
const searchRegex = new RegExp(searchTerm, 'i');
78-
if(searchTerm){
79-
articles= pickBy(articles, (value) => {
75+
if (searchTerm) {
76+
articles = pickBy(articles, (value) => {
8077
return value.title.match(searchRegex) ||
81-
value.body.match(searchRegex);
78+
value.body.match(searchRegex);
8279
});
8380
}
8481
return (
8582
<div>
86-
<Timestamp />
87-
<SearchBar key="searchBar" />
83+
<Timestamp/>
84+
<SearchBar key="searchBar"/>
8885
<ArticleList key="articleList"
8986
articles={articles}
90-
/>
87+
/>
9188
</div>
9289
);
9390
}

lib/components/Article.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,27 @@ const dateDisplay = (dateString) => new Date(dateString).toDateString();
3131

3232
//********** Presentational Component ****************
3333
//Reads the context from props so It is easy to shallow test it
34-
const Article = (props) => {
35-
const {article, author} = props;
36-
34+
class Article extends React.PureComponent {
3735

3836
//Ideally there should not be operations or functions here
39-
return (
40-
<div style={styles.article}>
41-
<div style={styles.title}>{article.title}</div>
42-
<div style={styles.date}>
43-
{dateDisplay((article.date))}
44-
{article.date}
37+
render() {
38+
const {article, author} = this.props;
39+
return (
40+
<div style={styles.article}>
41+
<div style={styles.title}>{article.title}</div>
42+
<div style={styles.date}>
43+
{dateDisplay((article.date))}
44+
{article.date}
45+
</div>
46+
<div style={styles.author}><a href={author.website}>
47+
{author.firstName} {author.lastName}
48+
</a></div>
49+
<div style={styles.body}>{article.body}</div>
4550
</div>
46-
<div style={styles.author}><a href={author.website}>
47-
{author.firstName} {author.lastName}
48-
</a></div>
49-
<div style={styles.body}>{article.body}</div>
50-
</div>
51-
);
52-
};
51+
);
52+
}
53+
}
54+
5355

5456
Article.propTypes = {
5557
article: PropTypes.shape({
@@ -59,12 +61,12 @@ Article.propTypes = {
5961
})
6062
};
6163

62-
function extraProps (store, originalProps){
64+
function extraProps(store, originalProps) {
6365
return {
6466
author: store.lookupAuthor(originalProps.article.authorId)
6567
};
6668
}
6769

6870
//This is similar as connect in Redux
69-
const ArticleContainer = storeProvider (extraProps)(Article);
71+
const ArticleContainer = storeProvider(extraProps)(Article);
7072
export default ArticleContainer;

lib/components/ArticleList.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import React from 'react';
22
import Article from './Article';
33

4-
const ArticleList = (props) => {
5-
return (
6-
<div>
7-
{Object.values(props.articles).map( (article) =>
8-
<Article key={article.id}
9-
article={article}/>
10-
)}
11-
</div>
12-
);
13-
};
4+
class ArticleList extends React.PureComponent
5+
{
6+
render()
7+
{
8+
return (
9+
<div>
10+
{Object.values(this.props.articles).map((article) =>
11+
<Article key={article.id}
12+
article={article}/>
13+
)}
14+
</div>
15+
);
16+
}
17+
}
1418

1519
export default ArticleList;

lib/components/SearchBar.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import debounce from 'lodash.debounce';//NOTE: we are just importing the debounce function from lodash not the whole package
33
import storeProvider from './storeProvider';
44

5-
class SearchBar extends React.Component{
5+
class SearchBar extends React.PureComponent{
66

77
state={
88
searchTerm: ''
@@ -21,6 +21,19 @@ class SearchBar extends React.Component{
2121

2222
};
2323

24+
//In this case we can just convert this to a PureComponent which does the job described below for us.
25+
// shouldComponentUpdate(nextProps, nextState){
26+
// //if we just pass FALSE it will render but does not allow us to type anything as the component is not connected with teh tree
27+
// //return false;
28+
// //If we pass TRUE it will rerender everysecons as our state with the tick interval is updating the state and a normal component re-renders every time the state is updated.
29+
// //return true;
30+
// //To solve the issue we should compare current and next props as well as current and previosu state
31+
// }
32+
33+
componentWillUpdate(nextProps, nextState)
34+
{
35+
console.log('Updating SearchBar');
36+
}
2437

2538
//Option 1. We could read the value of the text typed by ref (getting the current DOM node)
2639
// ref={(input) => this.searchInput = input}

lib/components/Timestamp.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,29 @@
22
import React from 'react';
33
import storeProvider from './storeProvider';
44

5-
class Timestamp extends React.Component{
5+
class Timestamp extends React.PureComponent{
6+
7+
timeDisplay = (timestamp) => timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
8+
9+
//We will do a custom should component update so it just updates based on the time and minutes update
10+
shouldComponentUpdate(nextProps, nextState){
11+
//const currentTimeDisplay= this.props.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
12+
//const nextTimeDisplay= nextProps.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
13+
//So if it is different re render just every minute not every second
14+
//return currentTimeDisplay !== nextTimeDisplay;
15+
16+
//Simplified version
17+
return (this.timeDisplay(this.props.timestamp) !=
18+
this.timeDisplay(nextProps.timestamp));
19+
}
20+
21+
componentWillUpdate(nextProps, nextState)
22+
{
23+
console.log('Updating TimeStamp');
24+
}
25+
626
render(){
7-
return(<div>{this.props.timestamp.toString()}</div>);
27+
return(<div>{this.props.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'})}</div>);
828
}
929
}
1030

lib/components/storeProvider.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,24 @@ const storeProvider = (extraProps = () =>({})) => (Component) => {
1515
static displayName = `${Component.name}Container`;
1616
static contextTypes = {store: PropTypes.object};
1717

18+
usedState = () => {
19+
return extraProps(this.context.store, this.props);
20+
};
21+
22+
state = this.usedState();
23+
1824

1925
onStoreChange=()=>{
20-
//Give the component the signal that it needs to re-render
21-
this.forceUpdate();
26+
if(this.subsciptionId) {
27+
//Give the component the signal that it needs to re-render
28+
//this.forceUpdate();
29+
this.setState(this.usedState());
30+
}
2231
}
2332

2433
componentDidMount(){
2534
//we need to update the component state so the app component state is in sync to the store state
26-
if(this.subsciptionId) {
27-
this.subsciptionId = this.context.store.subscribe(this.onStoreChange);
28-
}
35+
this.subsciptionId = this.context.store.subscribe(this.onStoreChange);
2936
}
3037

3138
componentWillUnmount(){
@@ -36,7 +43,7 @@ const storeProvider = (extraProps = () =>({})) => (Component) => {
3643
render(){
3744
return <Component
3845
{...this.props}
39-
{...extraProps(this.context.store, this.props)}
46+
{...this.usedState()}
4047
store={this.context.store}/>;
4148
}
4249
};

0 commit comments

Comments
 (0)