Skip to content

Commit 4200b1c

Browse files
Subscribing to the portion of the state each component needs (Store-external state and App Global State)
1 parent dd4c42e commit 4200b1c

File tree

9 files changed

+7524
-1693
lines changed

9 files changed

+7524
-1693
lines changed

lib/components/App.js

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
import React from 'react';
44
import PropTypes from 'prop-types';
55
import pickBy from 'lodash.pickby';
6+
import Perf from 'react-addons-perf';
7+
8+
if(typeof window !== 'undefined') {
9+
window.Perf = Perf;
10+
}
611

712
import ArticleList from './ArticleList';
813
import SearchBar from './SearchBar';
914
import Timestamp from './Timestamp';
1015

11-
class App extends React.Component {
16+
class App extends React.PureComponent {
1217

1318
//****** I need the following lines to expose the CONTEXT
1419
//to make the context api work we need to define the context type
@@ -22,25 +27,48 @@ class App extends React.Component {
2227
store: this.props.store
2328
};
2429
}
25-
2630
//********
2731

28-
state = this.props.store.getState();
32+
33+
//**** Subscribing to a portion of the state,
34+
//pretty much just returning what we really need as a state for this particular component
35+
appState =()=>{
36+
const {articles, searchTerm} = this.props.store.getState();
37+
return {articles, searchTerm};
38+
};
39+
40+
state = this.appState();
41+
//****
42+
2943

3044
onStoreChange = () => {
31-
this.setState(this.props.store.getState);
45+
//this.props.store.getState....we dont need to read directly from the props state but our own implementation
46+
this.setState(this.appState);
3247
}
3348

3449
componentDidMount() {
3550
//we need to update the component state so the app component state is in sync to the store state
3651
this.subsciptionId = this.props.store.subscribe(this.onStoreChange);
3752
this.props.store.startClock();
53+
54+
55+
//TODO: Leaving this purposely uncommented. Be aware that in production this has to be commented.
56+
//We need consistent measures that's why we need to add this lines so we messure the components at the same point
57+
//Those numbers need to be the same every time we refresh
58+
setImmediate(()=>{Perf.start();});
59+
setTimeout(()=>{ Perf.stop();
60+
Perf.printWasted();},5000);
3861
}
3962

4063
componentWillUnmount() {
4164
this.props.store.unsubscribe(this.subscriptionId);
4265
}
4366

67+
componentWillUpdate(nextProps, nextState)
68+
{
69+
console.log('Updating TimeStamp');
70+
}
71+
4472
//In react we cannot return two elements unless
4573
//Option 1. is in an array so we need to pass a Key elements
4674
// render() {
@@ -68,6 +96,15 @@ class App extends React.Component {
6896
// we can make a StateApi an event emmiter (Flux)
6997
// or manage subscriptions in the same object
7098

99+
100+
//To solve rendering the articles if the properties have not changed
101+
//Just re-render if you need to
102+
//Downside is that we will have to update this method if we have another property
103+
// shouldComponentUpdate(nextProps, nextState){
104+
// return (nextState.articles !== this.state.articles ||
105+
// nextState.searchTerm !== this.state.searchTerm);
106+
// }
107+
71108
render() {
72109
let {articles, searchTerm} = this.state;
73110
//making the search case insensitive

lib/components/Article.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Article.propTypes = {
6161
})
6262
};
6363

64+
//We are using props that do not use the state
6465
function extraProps(store, originalProps) {
6566
return {
6667
author: store.lookupAuthor(originalProps.article.authorId)

lib/components/Timestamp.js

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

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

7-
timeDisplay = (timestamp) => timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
7+
static timeDisplay = (timestamp) => timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
88

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;
159

16-
//Simplified version
17-
return (this.timeDisplay(this.props.timestamp) !=
18-
this.timeDisplay(nextProps.timestamp));
19-
}
10+
//This logic is causing the Timestamp component to render every minute, in order to avoid that we
11+
//will move the ShouldComponentUpdate one level up to the Container Component
12+
13+
14+
// //We will do a custom should component update so it just updates based on the time and minutes update
15+
// shouldComponentUpdate(nextProps, nextState){
16+
// //const currentTimeDisplay= this.props.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
17+
// //const nextTimeDisplay= nextProps.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'});
18+
// //So if it is different re render just every minute not every second
19+
// //return currentTimeDisplay !== nextTimeDisplay;
20+
//
21+
// //Simplified version
22+
// return (this.timeDisplay(this.props.timestamp) !=
23+
// this.timeDisplay(nextProps.timestamp));
24+
// }
25+
2026

21-
componentWillUpdate(nextProps, nextState)
22-
{
23-
console.log('Updating TimeStamp');
24-
}
2527

2628
render(){
27-
return(<div>{this.props.timestamp.toLocaleTimeString([],{hour: '2-digit', minute:'2-digit'})}</div>);
29+
return(<div>{this.props.timestampDisplay}</div>);
2830
}
2931
}
3032

33+
//We are using props that use the state (Contrary to articles List )
3134
function extraProps(store)
3235
{
36+
//This is the only component that is actually making use of the state
37+
//timestamp: store.getState().timestamp
3338
return {
34-
timestamp: store.getState().timestamp
39+
40+
timestampDisplay: Timestamp.timeDisplay(store.getState().timestamp)
3541
};
3642
}
3743

lib/components/__tests__/ArticleList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react';
33
//import renderer from 'react-test-renderer';
44
import ArticleList from '../ArticleList';
55
import { configure, shallow } from 'enzyme';
6-
import Adapter from 'enzyme-adapter-react-16';
6+
import Adapter from 'enzyme-adapter-react-15';
77

88
configure({ adapter: new Adapter() });
99

lib/components/storeProvider.js

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

18+
19+
//only the properties of the state that have been used for the warp component
1820
usedState = () => {
1921
return extraProps(this.context.store, this.props);
2022
};
@@ -40,6 +42,8 @@ const storeProvider = (extraProps = () =>({})) => (Component) => {
4042
this.subscriptionId = null;
4143
}
4244

45+
46+
4347
render(){
4448
return <Component
4549
{...this.props}

lib/state-api/lib/index.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ class StateApi{
77
authors: this.mapIntoObject(rawData.authors),
88
searchTerm :'',
99
timestamp: new Date()};
10-
1110
this.subscriptions ={};
12-
1311
this.lastSubscriptionId=0;
14-
15-
1612
}
1713

1814

0 commit comments

Comments
 (0)