diff --git a/src/App.tsx b/src/App.tsx index c899da4..761cff9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,29 @@ import React from "react"; -import logo from "./logo.svg"; import "./App.scss"; +import { useGlobalState } from "./state/useGlobalState"; +import { UpdateUserName, UpdateUserAge } from "./state/user/UserActions"; function App() { + const {state, dispatch} = useGlobalState(); + + const updateName = () => { + dispatch(new UpdateUserName('Emanuel')) + } + + const updateAge = () => { + dispatch(new UpdateUserAge(30)) + } + + return (
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
+ +

+ Current name: {state.user.name}
+ Current age: {state.user.age}
); } export default App; + diff --git a/src/index.tsx b/src/index.tsx index 3125ee4..fd37a4e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,11 +3,16 @@ import ReactDOM from "react-dom"; import "./index.scss"; import App from "./App"; import * as serviceWorker from "./serviceWorker"; +import { Provider } from "./state/Provider"; + + ReactDOM.render( - - - , + + + + + , document.getElementById("root") ); diff --git a/src/state/Action.ts b/src/state/Action.ts new file mode 100644 index 0000000..51ae1d2 --- /dev/null +++ b/src/state/Action.ts @@ -0,0 +1,3 @@ +export interface Action { + readonly type: string; +} \ No newline at end of file diff --git a/src/state/Context.ts b/src/state/Context.ts new file mode 100644 index 0000000..c23748f --- /dev/null +++ b/src/state/Context.ts @@ -0,0 +1,12 @@ +import React, { createContext } from 'react'; +import { State, initialState } from './State'; +import { Action } from './Action'; + + + +const initialContext: { state: State; dispatch: React.Dispatch } = { + state: initialState, + dispatch: () => {} +}; + +export const Context = createContext(initialContext); \ No newline at end of file diff --git a/src/state/Provider.tsx b/src/state/Provider.tsx new file mode 100644 index 0000000..a388d2c --- /dev/null +++ b/src/state/Provider.tsx @@ -0,0 +1,10 @@ + +import React, { useReducer } from 'react'; +import { Context } from './Context'; +import { initialState } from './State'; +import { reducer } from './Reducer'; + +export function Provider({ children }: any) { + const [state, dispatch] = useReducer(reducer, initialState); + return {children}; + } \ No newline at end of file diff --git a/src/state/Reducer.ts b/src/state/Reducer.ts new file mode 100644 index 0000000..137e9a3 --- /dev/null +++ b/src/state/Reducer.ts @@ -0,0 +1,19 @@ +import { UserReducer } from "./user/UserReducer"; +import { State } from "./State"; + +export const combineReducers = (reducers: {[P in keyof T]: any}) => { + const reducerEntries = Object.entries(reducers) as [keyof T, any][]; + return (state: T, action: any) => { + const nextState = {} as T; + for(const [key, reducer] of reducerEntries){ + const previousStateForKey = state[key]; + const nextStateForKey = reducer(previousStateForKey, action) + nextState[key] = nextStateForKey; + } + return nextState; + } +} + + export const reducer = combineReducers({ + user: UserReducer, + }) \ No newline at end of file diff --git a/src/state/State.ts b/src/state/State.ts new file mode 100644 index 0000000..2cd46e6 --- /dev/null +++ b/src/state/State.ts @@ -0,0 +1,9 @@ +import { UserState, initialUserState } from "./user/UserState"; + +export interface State { + user: UserState +} + +export const initialState: State = { + user: initialUserState +} \ No newline at end of file diff --git a/src/state/useGlobalState.ts b/src/state/useGlobalState.ts new file mode 100644 index 0000000..cb7a72d --- /dev/null +++ b/src/state/useGlobalState.ts @@ -0,0 +1,5 @@ +import { useContext } from 'react'; +import { Context } from './Context'; + + +export const useGlobalState = () => useContext(Context); \ No newline at end of file diff --git a/src/state/user/UserActions.ts b/src/state/user/UserActions.ts new file mode 100644 index 0000000..3f5fff0 --- /dev/null +++ b/src/state/user/UserActions.ts @@ -0,0 +1,22 @@ +import { Action } from "../Action"; + +export enum UserActionTypes { + UpdateUserName = "[User] Update User name", + UpdateUserAge = "[User] Update User age" + +} + + + +export class UpdateUserAge implements Action{ + public readonly type = UserActionTypes.UpdateUserAge; + constructor(public age: number) { } +} + +export class UpdateUserName implements Action{ + public readonly type = UserActionTypes.UpdateUserName; + constructor(public name: string) { } +} + + +export type UserActions = UpdateUserName | UpdateUserAge; \ No newline at end of file diff --git a/src/state/user/UserReducer.ts b/src/state/user/UserReducer.ts new file mode 100644 index 0000000..8e3c525 --- /dev/null +++ b/src/state/user/UserReducer.ts @@ -0,0 +1,20 @@ +import { UserActionTypes, UserActions } from "./UserActions"; +import { UserState } from "./UserState"; + +export const UserReducer = (state: UserState, action: UserActions) => { + switch (action.type) { + case UserActionTypes.UpdateUserAge: + return { + ...state, + age: action.age + }; + case UserActionTypes.UpdateUserName: + return { + ...state, + name: action.name + }; + default: + return state; + } + }; + \ No newline at end of file diff --git a/src/state/user/UserState.ts b/src/state/user/UserState.ts new file mode 100644 index 0000000..8cf27b7 --- /dev/null +++ b/src/state/user/UserState.ts @@ -0,0 +1,10 @@ +export type UserState = { + age: number; + name: string; + }; + + export const initialUserState: UserState = { + age: 12, + name: "Initial name" + } + \ No newline at end of file