Skip to content

Instantly share code, notes, and snippets.

@jjzazuet
Created January 2, 2019 23:05
Show Gist options
  • Save jjzazuet/44ea3b0350f373252ca967ab1623945f to your computer and use it in GitHub Desktop.
Save jjzazuet/44ea3b0350f373252ca967ab1623945f to your computer and use it in GitHub Desktop.
React with Redux in Typescript - wiring draft
/* ======== Start with action definitions ======== */
import {Action} from "redux";
import {ThunkAction, ThunkDispatch} from "redux-thunk";
import {RootState} from "gopher/state";
export enum Ui { LOCK, ERROR }
export enum Auth { USER_LOAD_START, USER_LOAD_END, AUTH_RESTART }
export type ActionType = Ui | Auth;
export interface FluxAction<T extends ActionType, P = any> extends Action<T> { payload: P; }
export interface UiLock extends FluxAction<typeof Ui.LOCK, boolean> {}
export type AppAction = UiLock; // | whatever else...
type TA<T extends ActionType, P> = ThunkAction<Promise<P>, RootState, null, FluxAction<T, P>>;
export type TD<T extends ActionType, P> = ThunkDispatch<RootState, null, FluxAction<T, P>>;
export interface DispatchProps { dispatch: TD<ActionType, any>; } // to inject into connected React components
export const hit = <T extends ActionType, P>(type: T, params: P): TA<T, P> => // to execute all actions as chained promises
(dispatch) => {
dispatch({type, payload: params});
return Promise.resolve(params);
};
export const lockUi = (toggleState: boolean) => hit(Ui.LOCK, toggleState);
/* ======== Define base state and reducer ======== */
import {Reducer} from "redux";
import {AppAction, Ui} from "somewhere/actions";
export interface UiState {
uiLocked: boolean;
}
const baseState: UiState = {uiLocked: false};
export const baseReducer: Reducer<UiState, AppAction> = (state = baseState, action) => {
switch (action.type) {
case Ui.LOCK:
return {...state, uiLocked: action.payload};
default: return state;
}
};
/* ======== Assemble base state and store ======== */
import {UiState} from "somewhere/reducer";
export interface RootState {
base: UiState;
}
//// ////
import {applyMiddleware, combineReducers, createStore} from "redux";
import {createLogger} from "redux-logger";
import thunkMiddleware from "redux-thunk";
import {baseReducer} from "somewhere/reducer";
import {RootState} from "somewhere/state";
const rootReducer = combineReducers<RootState>({
base: baseReducer
});
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware, createLogger()
)(createStore);
export default (initialState: RootState) => createStoreWithMiddleware(rootReducer, initialState);
/* ======== Create and connect a component to the Redux state tree ======== */
import * as React from "react";
import {connect} from "react-redux";
import {ActionType, DispatchProps, lockUi, TD} from "somewhere/actions";
import {UiState} from "somewhere/reducer";
import {RootState} from "somewhere/state";
class Hello extends React.Component<UiState & DispatchProps> {
public componentDidMount() {
const d = this.props.dispatch;
d(lockUi(true)).then((lol) => d(lockUi(!lol)));
}
public render() {
return <h1>Hello</h1>;
}
}
export default connect(
(rs: RootState): UiState => rs.base,
(dispatch: TD<ActionType, any>): DispatchProps => ({dispatch})
)((Hello));
/* ======== Mount the main app ======== */
import * as React from "react";
import * as ReactDOM from "react-dom";
import {Provider} from "react-redux";
import Hello from "somewhere/components/Hello";
import configureStore from "somewhere/store";
ReactDOM.render(
<Provider store={configureStore({} as any)}>
<Hello />
</Provider>, document.getElementById("root")
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment