Weitere ähnliche Inhalte
Ähnlich wie Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016) (20)
Kürzlich hochgeladen (20)
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
- 46. function handleChange(action) {
...
switch (action.type) {
case JobActions.APPLY:
job.set('state', States.APPLIED);
break;
...
}
JobStore.emitChange();
}
JobStore.dispatchToken = MyJobsDispatcher.register(handleChange);
Update Job Store
Transition Job
Dispatcher
Job Store
Job Row
- 49. const changeAggregator = new ChangeAggregator(
MyJobsDispatcher, storesToListenTo
);
const MainDisplay = React.createClass({
componentDidMount() {
changeAggregator.addChangeListener(this.update);
}
...
});
Collect changes
- 50. const MainDisplay = React.createClass({
...
update() {
this.setState({
jobs: JobStore.getJobs(),
counts: JobCountStore.getCounts(),
...
});
}
});
Transition Job
Dispatcher
Job StoreJob Count Store
Job Row
View List Job Table
Update views
- 53. Best Practices & Testability
// TODO: Should this be in a different place..?
window.scrollTo(0, 0);
ViewStore.emitChange();
ViewStore.js
- 65. Single source of truth
const createStore = (reducer) => {
let state = {};
const getState = () => state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
}
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
return {getState, dispatch, subscribe};
}
- 66. State is read only
const createStore = (reducer) => {
let state = {};
const getState = () => state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
}
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
return {getState, dispatch, subscribe};
}
- 67. Changes are made with pure functions
const createStore = (reducer) => {
let state = {};
const getState = () => state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
}
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
return {getState, dispatch, subscribe};
}
- 68. Emit changes
const createStore = (reducer) => {
let state = {};
const getState = () => state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
}
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
return {getState, dispatch, subscribe};
}
- 69. Single reducer
const createStore = (reducer) => {
let state = {};
const getState = () => state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
}
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
return {getState, dispatch, subscribe};
}
- 70. const myjobsReducer(state = new AppState(), action) => {
state = state.set('jobs', jobsReducer(state.jobs, action));
state = state.set('jobCounts', jobCountsReducer(state.jobCounts, action, state.jobs));
...
return state;
}
Combining reducers
- 71. const myjobsStore = createStore(myjobsReducer);
<MainDisplay
store={myjobsStore}
...
/>
Store as an explicit prop
- 72. const myjobsStore = createStore(myjobsReducer);
<MainDisplay
store={myjobsStore}
...
/>
<ViewList
store={this.props.myjobsStore}
...
/>
Store as an explicit prop
- 73. const myjobsStore = createStore(myjobsReducer);
<MainDisplay
store={myjobsStore}
...
/>
<ViewList
store={this.props.myjobsStore}
...
/>
<JobTable
store={this.props.myjobsStore}
...
/>
Store as an explicit prop
- 75. const myjobsStore = createStore(myjobsReducer);
<Provider store={myjobsStore}>
<MainDisplay />
</Provider>
react-redux Provider
JobRow
MainDisplay
ViewListJobTable
Provider
myjobsStore
Provided store: {myjobsStore}
- 83. Connect
...
render() {
this.renderedElement = createElement(
WrappedComponent, this.mergedProps
);
return this.renderedElement;
}
mergedProps: {
...parentProps,
...mapStateToProps,
...mapDispatchToProps
}
react-redux connect
- 84. import { connect } from 'react-redux';
...
const matchStateToProps => (state) {
return {
jobsState: state.jobs
};
}
module.exports = connect(matchStateToProps)(JobTable);
JobTable.js
- 88. const createStore = (reducer) => {
...
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
}
myjobsStore
{type:"APPLY",jobKey:"7b14...",...}
Job Row
- 89. const createStore = (reducer) => {
...
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
}
Job Row
myjobsStore
myjobsReducer
state
- 90. const createStore = (reducer) => {
...
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
}
Job Row
myjobsStore
myjobsReducer
state
newState
- 91. const createStore = (reducer) => {
...
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
}
JobTable
Job Row
myjobsStore
myjobsReducer
state
newState
- 98. Well unit tested state transition logic
Less code to maintain
Code easier to follow
Results