- Suspense
- HOCs (lazy, memo)
- Hooks
- Concurrent Mode
- Fiber Architecture
-
Title - parent node
-
It would render the whole app, then create VDOM tree from the render output, then connect to real DOM tree.
-
Adapted by Vue, Elm, Hyper, etc.
-
Problem is it blocks the main thread process.
-
Two phases: Render phase and commit phase
-
Render phase, not eager, it gives time for higher-priorirty process to happen.
-
Once render phase, commit phase happens.
-
Render phase: render function (functional components or render method of classes), constructors
-
Commit phase: Lifecycle methods (componentDidMount) and effect hooks (useEffect and useLayoutEffect)
useEffect(() => {
const listener = () => {
setState((current) => {
if (!is(current, store.getValue())) {
return store.getValue();
}
return current;
});
};
// Let's assume that the state has changed at this point
listener();
// Further updates
const unsubscribe = subscribe(listener);
return unsubscribe;
}, [store, subscribe])
- render per component, commit immediately
- hydration
- getServerSideProps -> renderToHTML -> hydrate (connect pre-rendered tree to the initial VDOM tree)
ReactDOM.render(<App />, document.getElementById(root));
const root = ReactDOM.createRoot(document.getElementById(root));
root.render(<App />)
const { data, error } = useSWR(`/api/user`);
render-then-fetch
const [data, setData] = useState();
const [error, setError] = useState();
useEffect(() => {
fetcher().then(setData, setError);
}, []);
return { data, error };
function UserDetails() {
// ???
const userDetails = userDetailsFetcher.read();
return (
<>
<h1>{userDetails.name}</h1>
<h1>{userDetails.age}</h1>
</>
);
}
<Suspense fallback={<h1>Loading</h1>}>
<UserDetails />
</Suspense>
- memorize a single value/reference for the whole lifecycle
- refs are not reactive.
- capturing DOM
- states
- reactive
- bail-out mechanism
const [count, dispatch] = useReducer((state, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}, 0);
- useEffect != componentDidMount
- Always ideal for side-effects
- Only runs once on strict mode and concurrent mode
- useEffect always runs after useLayoutEffect
- useLayoutEffect == componentDidMount
useLayoutEffect(() => {
inputRef.current.addEventListener('click', listener);
}, []);
<input ref={inputRef}>
- Presents debug value on devtools
- Receives the forwarded ref, decorates value
const Input = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
value: inputRef.current.value,
}));
});
- memoizes a value from a function
- recomputes when dependencies change
- unstable
useConstant(expensiveFunc);
const value = useMemo(expensiveFunc, []);
<div onClick={() => {
// ...
}}>
const Example = createContext({ a: 'Hello', b: 'World' }, (prev, next) => {
if (prev.a !== next.a) {
return 0b01;
}
if (next.b !== prev.b) {
return 0b10;
}
return 0b00;
});
//
const { a } = useContext(Example, 0b01);
//
const value = useContext(Example, (state) => newState);