Skip to content

Instantly share code, notes, and snippets.

@d6u
Last active May 16, 2016 21:50
Show Gist options
  • Select an option

  • Save d6u/3ca85ed927bd458c7068b8e75e43ed8e to your computer and use it in GitHub Desktop.

Select an option

Save d6u/3ca85ed927bd458c7068b8e75e43ed8e to your computer and use it in GitHub Desktop.
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider, connect} from 'react-redux';
import set from 'lodash/fp/set';
const ADD_TAG = 'ADD_TAG';
const repos = require('json!./repos.json');
const store = createStore((state = {repos}, action) => {
switch (action.type) {
case ADD_TAG:
return set('repos[0].tags[0]', {
id: 213,
text: 'Node.js'
}, state);
default:
return state;
}
});
class Repo extends React.Component {
shouldComponentUpdate(nextProps) {
return this.props.repo !== nextProps.repo;
}
render() {
const {repo} = this.props;
const [authorName, repoName] = repo.full_name.split('/');
return (
<li className="repo-item">
<div className="repo-full-name">
<span className="repo-name">{repoName}</span>
<span className="repo-author-name"> / {authorName}</span>
</div>
<ol className="repo-tags">
{repo.tags.map((tag) => <li className="repo-tag-item" key={tag.id}>{tag.text}</li>)}
</ol>
<div className="repo-desc">{repo.description}</div>
</li>
);
}
}
const RepoList = ({repos}) => {
return <ol className="repos">{repos.map((repo) => <Repo repo={repo} key={repo.id}/>)}</ol>;
};
const App = connect((state) => state)(RepoList);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('app')
);
setTimeout(() => {
console.time('DISPATCH');
store.dispatch({
type: ADD_TAG
});
console.timeEnd('DISPATCH');
}, 1000);
[
{
"id": 1,
"full_name": "ljharb/qs",
"description": "A querystring parser with nesting support",
"homepage": "",
"html_url": "https://github.com/ljharb/qs",
"tags": [
{
"id": 1,
"text": "JavaScript",
"foreground_color": null,
"background_color": null
}
],
"starred_at": 1462766927
},
... just an example ...
]

How to optimize small updates to props of nested component?

I have above components, Repo and RepoList. I want to update the tag of the first repo (Line 14). So I dispatched an ADD_TAG action. Before I implemented shouldComponentUpdate, the dispatch takes about 200ms, which is expacted since we are wasting lots of time diffing <Repo/>s that haven't changed.

After added shouldComponentUpdate, dispatch takes about 30ms. This is much better, but imagine if we have many updates like this, or <Repo/> is more complicated than current one, we won't be able to maintain 60fps.

My question is, for such small udpates to a nested component's props, is there a more efficient way to update the content? Can I still use Redux?

@d6u
Copy link
Author

d6u commented May 16, 2016

I got a solution by replacing every tags with an observable inside reducer. Something like

// inside reducer when handling ADD_TAG action
// repos[0].tags of state is already replaced with a Rx.BehaviorSubject
get('repos[0].tags', state).onNext([{
  id: 213,
  text: 'Node.js'
}]);

Then I subscribe to their values inside Repo component using https://github.com/jayphelps/react-observable-subscribe. This worked great. Every dispatch only costs 5ms. But I feel like this is an anti-pattern in Redux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment