-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuse-methods.js
42 lines (33 loc) · 2.43 KB
/
use-methods.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React, { useCallback, useReducer } from "react"
import setOrDelete from "./set-or-delete"
// while "object" state (a pointer for you C programmers) will change each time, the object state.methodState (meaning the pointer methodState) will always be the same
// this reducer will mutate the contents of the methodState object based on the properties in the object "action'. So action does not have a type like it would in other cases.
// reducer will retun a new state but with the same methodState object - though it will be mutated
function reducer(state, action) {
setOrDelete(state.methodState, action) // dispath calls may get queued and executed in batch, key: undefined deletes an property
return { ...state }
}
export function useMethods(methodsObj, initialState, deps = []) {
// useReducer returns a new pointer to "state" every time state changes, but it always returns the same value for dispatch
const [state, dispatch] = useReducer(reducer, { methodState: initialState })
// these methods (the code) are setup once. They will always refer to the original "state" pointer that was returned by the very first useReducer call.
// but because our "state" has "methodState" in it, and our reducer always mutates that object (rather then setting methodState= it uses objectAssign(methodState))
// these "memorized" methods will be able to access the latest *methodState* as it changes
// memorizing these methods saves times and reduces rerendering of components
// writing code with methods is less work and less error prone than doing dispatch({type: "xxx"}) everywhere
const methodState = state.methodState // now you don't have to say state.methodState everywhere
const methods = useCallback(methodsObj(dispatch, methodState), deps) // dispatch and methodState aren't in deps because they never change
methods.reset = function () {
// reset the methodState back to initialState by mutating the original object.
// don't create a new object, becasue the methosObjs were instantiated to work with the original state.methodState object.
Object.keys(state.methodState).forEach((key) => {
delete state.methodState[key]
})
Object.assign(state.methodState, initialState)
dispatch({})
}
// methodsObj is a function that returns an object of methods - because we need to pass dispatch to it. Passing methodState doesn't hurt
return [methodState, methods]
}
export default useMethods
export { setOrDelete }