function createStore(reducer) {
let state = undefined;
const listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
};
dispatch({});
return {
getState,
dispatch,
subscribe
};
}
function connect(mapStateToProps, mapDispatchToProps) {
return function(Component) {
class ConnectedComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = mapStateToProps(context.getState());
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
const newState = mapStateToProps(this.context.getState());
this.setState(newState);
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { dispatch } = this.context;
const additionalProps = mapDispatchToProps(dispatch);
return <Component {...this.props} {...this.state} {...additionalProps} />;
}
}
ConnectedComponent.contextType = ReduxContext;
return ConnectedComponent;
};
}
const ReduxContext = React.createContext();
class Provider extends React.Component {
render() {
const { store, children } = this.props;
return (
<ReduxContext.Provider value={store}>
{children}
</ReduxContext.Provider>
);
}
}
const store = createStore(reducer);
const increment = () => ({ type: 'INCREMENT' });
const decrement = () => ({ type: 'DECREMENT' });
function reducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
const ConnectedCounter = connect(
state => ({ count: state }),
dispatch => ({
onIncrement: () => dispatch(increment()),
onDecrement: () => dispatch(decrement())
})
)(Counter);
ReactDOM.render(
<Provider store={store}>
<ConnectedCounter />
</Provider>,
document.getElementById('root')
);