Skip to content

Instantly share code, notes, and snippets.

@iannbing
Created July 19, 2019 14:58
Show Gist options
  • Save iannbing/18e1f888b7ee4f419bf0d1e284152888 to your computer and use it in GitHub Desktop.
Save iannbing/18e1f888b7ee4f419bf0d1e284152888 to your computer and use it in GitHub Desktop.
A minimal implementation of react-redux using Context API
import { Provider } from './store';
import reducer from './reducer';
const initialState = { firstName: 'Jon', lastName: 'Snow', email: '[email protected]' }
const App = () => (<Dashboard>
<Provider reducer={reducer} initialState={initialState} >
<Header>
<UserProfile />
</Header>
</Provider>
</Dashboard>);
const SET_USERNAME = 'action/set_username';
export default function reducer(state, action){
const { type, payload } = action;
switch(type){
case SET_USERNAME: {
const { firstName, lastName } = payload;
return {...state, firstName, lastName};
}
default: {
return state;
}
}
}
// Action creator
export const setUsernameAction = ({ firstName, lastName }) => ({ type: SET_USERNAME, payload: { firstName, lastName } });
import React from "react";
const Context = React.createContext({});
const { Provider: InitialProvider, Consumer } = Context;
class Provider extends React.Component {
constructor(props) {
super(props);
const { initialState } = props;
this.state = initialState;
}
dispatch = async action => {
const { reducer } = this.props;
const { type, payload } = await action;
this.setState(state => reducer(state, { type, payload }));
return payload;
};
render() {
const { children } = this.props;
const context = { ...this.state, dispatch: this.dispatch };
return <InitialProvider value={context}>{children}</InitialProvider>;
}
}
const defaultmapStateToProps = state => state;
const defaultMergeProps = (stateProps, dispatchProps, ownProps) => ({
...stateProps,
...dispatchProps,
...ownProps
});
const defaultMapDispatchToProps = () => null;
const connect = (
mapStateToProps,
mapDispatchToProps,
mergeProps
) => Wrapped => ownProps => {
const mapStateToPropsFun = mapStateToProps || defaultmapStateToProps;
const mapDispatchToPropsFun =
mapDispatchToProps || defaultMapDispatchToProps;
const mergePropsFun = mergeProps || defaultMergeProps;
return (
<Consumer>
{({ dispatch, ...state }) => {
const stateProps = mapStateToPropsFun(state);
const dispatchProps = mapDispatchToPropsFun(dispatch, ownProps);
const merged = mergePropsFun(
stateProps,
dispatchProps,
ownProps
);
return (
<Wrapped
{...ownProps}
{...stateProps}
{...dispatchProps}
{...merged}
dispatch={dispatch}
/>
);
}}
</Consumer>
);
};
export { Provider, Consumer, connect };
import { setUsernameAction } from './path/to/your/reducer';
const UserProfile = ({ username, email, setUsername }) => {
return (
<div>
<div>
<div>User Name: {username}</div>
<div>Email: {email}</div>
</div>
<button onClick={() => setUsername({firstName: 'Kit', lastName: 'Harington'})}>
Rename to Kit Harington
</button>
</div>
)
}
const mapStateToProps = state => {
const { firstName, lastName } = state;
return { username: firstName + ' ' + lastName }
}
const mapDispatchToProps = dispatch => ({
setUsername: newName => dispatch(setUsernameAction(newName)),
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(React.memo(UserProfile));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment