After learning React Hooks, useState, useEffect, useContext; redux and redux-thunk/redux-saga, mobx; some UI Lib, you may feel losing direction, just like me.
This article is about what could be helpful for improving your react skill.
Everything comes from indirection
We can solve any problem by introducing an extra level of indirection.
React contains already a few directions somehow:
-
useState
is a simplify ofuseReducer
-
useMemo
anduseCallback
can be implemented byuseRef
However, if we regard these hooks as a default base layer, the hooks can be divided to six directions:
- base build-in layer from React official.
- hooks to simplify the state update, like immer.js for immutability.
- Use "state + behavior" concept, build a complex context by declaration.
- Encapsulation of data structure, like manipulation of arrays.
- Encapsulation of scene, like padination arrays, multiple checkbox.
- Implement to real scene.
Use immer.js to update state
Problem: Hard to update a state deep in a object when you want to keep the immutability.
const newValue = {
...oldValue,
foo: {
...oldValue?.foo,
bar: {
...oldValue?.foo?.bar,
alice: newAlice
},
},
};
Solution: write hooks using immer.js (or use community version).
const [state, setState] = useImmerState({foo: {bar: 1}});
setState(s => s.foo.bar++);
setState({foo: {bar: 2}});
const [state, dispatch] = useImmerReducer(
(state, action) => {
case 'ADD':
state.foo.bar += action.payload;
case 'SUBTRACT':
state.foo.bar -= action.payload;
default:
return;
},
{foo: {bar: 1}}
);
dispatch('ADD', {payload: 2});
Encapsulation of state and behavior
Most development of components and feature implements belongs to the pattern "one state + a serious of behavior".
The state and the behaviors are strongly related.
This pattern is similar to class concept in OO.
In hooks, we write somehow like this:
const [name, setName] = useState('');
const [age, SetAge] = useState(0);
const birthday = useCallback(
() => {
setAge(age => age + 1);
},
[age]
);
Problems:
- Repeated
useState
anduseCallback
is bad for code reuse. - Hard to find the relationship between behavior and properties.
Solution: useMethods
is an encapsulation of one state and behaviors related to this state.
const userMethods = {
birthday(user) {
user.age++; // with immer.js
},
};
const [user, methods, setUser] = useMethods(
userMethods,
{name: '', age: 0}
);
methods.birthday();
Abstract of data structure
Problem:
- Some data structure's immutable manipulation is complex, like
Array.splice
. - Semantic changes. For example,
setState
doesn't return a value, whileArray.pop
returns the popped element. - Some types like
Set
andMap
are always mutable.
Solution: lots of hooks in community like useNumber
, useArray
, useSet
, useMap
, useBoolean
, useToggle
.
// A implement of useArray
const [list, methods, setList] = useArray([]);
interface ArrayMethods<T> {
push(item: T): void;
unshift(item: T): void;
pop(): void;
shift(): void;
slice(start?: number, end?: number): void;
splice(index: number, count: number, ...items: T[]): void;
remove(item: T): void;
removeAt(index: number): void;
insertAt(index: number, item: T): void;
concat(item: T | T[]): void;
replace(from: T, to: T): void;
replaceAll(from: T, to: T): void;
replaceAt(index: number, item: T): void;
filter(predicate: (item: T, index: number) => boolean): void;
union(array: T[]): void;
intersect(array: T[]): void;
difference(array: T[]): void;
reverse(): void;
sort(compare?: (x: T, y: T) => number): void;
clear(): void;
}
Ecaplutaion of general scene
For example
These ecaplutations should not coupled with UI components.
They are able to apply on different UI components/lib.
Top comments (0)