Last active
March 4, 2023 14:28
-
-
Save benceg/f85e5bfafb78b238d97d10ea3b209c67 to your computer and use it in GitHub Desktop.
Elm Pattern in React & TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-explicit-any */ | |
import { | |
ComponentProps, | |
Dispatch, | |
FC, | |
ReactElement, | |
Reducer, | |
ReducerAction, | |
ReducerState, | |
useReducer, | |
} from "react"; | |
export const ElmPattern = <T extends Reducer<any, any>>(props: { | |
children: ( | |
props: ReducerState<T> & { dispatch: Dispatch<ReducerAction<T>> } | |
) => ReactElement; | |
reducer: T; | |
initialState: ReducerState<T>; | |
}): ReactElement => { | |
const [state, dispatch] = useReducer(props.reducer, props.initialState); | |
return props.children({ dispatch, ...state }); | |
}; | |
export const elmify = | |
<C extends FC<any>, T extends ComponentProps<C>>(Component: C) => | |
(props: T) => | |
<Component {...props} />; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { elmify, ElmPattern } from "./ElmPattern"; | |
import { FC, Reducer } from "react"; | |
interface UserState { | |
name: string; | |
age: number; | |
} | |
const userReducer: Reducer< | |
UserState, | |
{ type: "incremented_age" } | { type: "changed_name"; nextName: string } | |
> = (state, action) => { | |
switch (action.type) { | |
case "incremented_age": | |
return { | |
name: state.name, | |
age: state.age + 1, | |
}; | |
case "changed_name": | |
return { | |
name: action.nextName, | |
age: state.age, | |
}; | |
} | |
}; | |
export const Component: FC<UserState> = ({ name, age }) => ( | |
<> | |
{name} is {age} years old | |
</> | |
); | |
const children = elmify(User); | |
const User: FC = () => ( | |
<ElmPattern reducer={userReducer} initialState={{ name: "", age: 0 }}> | |
{children} | |
</ElmPattern> | |
); | |
export default User; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment