In Component States and Dependencies under the Effect Paradigm, useState/useEffect is the most mentioned.

UseState/useEffect is the basis that drives render to trigger and run

This article starts from the implementation of simple useState/useEffect and discusses how they manage state and drive render.

Implement a useState manually

How is useState called?

const Comp = props= > {
	const [ foo, setFoo ] = useState(1);
	return <button onClick={()= > setFoo(2)}>{foo}</button>
};
Copy the code

UseState implements:

  • Pass in an initial state
  • Returns an array containing the latest state and set state methods.
  • Rerendering is triggered when the set state method is called

Very easy to implement

let currentState;
const useState = initialState= > {
	const state = currentState || initialState;
	const setState = newState= > {
		currentState = newState;
		render();	// This render can be interpreted as triggering the entire React app render, like reactdom.render ();
	};
	return [ state, setState ];
};
Copy the code

Storage box: compatible with multiple calls

It’s not that simple. In fact, useState is usually not called only once in the entire app, or even in a single component. It’s always the same useState implementation.

Assume that the order in which useState is called within your code is constant

That’s true in general. That’s easy. Just put them in the box in order.

Like wearing different socks seven days a week (one render) (seven useState). Put them in a storage box and go to the next box every day. Start all over again the next week (next render cycle).

let index = -1;
const currentStateBoxs = [];
const useState = initialState= > {
  index++;
  const currentIndex = index;
  currentStateBoxs[currentIndex] = currentStateBoxs[currentIndex] || initialState;
  const setState = newState= > {
    currentStateBoxs[currentIndex] = newState;
    render(); // This render can be interpreted as triggering the entire React app render, like reactdom.render ();
  };
  return [ currentStateBoxs[currentIndex], setState ];
};
Copy the code

Why not break the order of useState?

Imagine if you had no socks on one Tuesday and you wore the wrong ones on Wednesday…

const Comp = props= > {
	const[mondaysock] = useState(xx);// Get the first box of socks
	ifIt was fine on Tuesdayconst[tue sock] = useState(xx); }const[Wednesday sock] = useState(xx);// If not on Tuesday, take the second box of socks on Wednesday
};
Copy the code

The problem here is if, which makes the execution order of useState uncertain, as well as for and other conditions and loops.

Implement a useEffect manually

How is useEffect used?

const Comp = props= > {
	const [ foo, setFoo ] = useState(1);
	useEffect(() = >{... }, [ foo ]);return <button>{foo}</button>
};
Copy the code

UseEffect Executes a callback function when a dependency changes. This change is “dependency comparison between this render and last render”.

We need:

  • Store dependency, last render’s
  • Compatible with multiple calls, is also the idea of the box
  • More dependent, perform the callback function

Implementation:

const lastDepsBoxs = [];
let index = 0;
const useEffect = (callback, deps) = > {
	const lastDeps = lastDepsBoxs[index];
	constchanged = ! lastDeps// First render, must trigger| |! deps// Deps is not transmitted
		|| deps.some((dep, index) = >dep ! == lastDeps[index]);// Normal comparison
	if (changed) {
		lastDepsBoxs[index] = deps;
		callback();
	}
	index ++;
};
Copy the code

Increased side effect clearance

As mentioned in another article, when an effect is triggered, the cleanup function is temporarily saved until the next time an effect is triggered.

This sequence is not difficult to implement:

const lastDepsBoxs = [];
const lastClearCallbacks = [];
let index = 0;
const useEffect = (callback, deps) = > {
	const lastDeps = lastDepsBoxs[index];
	constchanged = ! lastDeps || ! deps || deps.some((dep, index) = >dep ! == lastDeps[index]);if (changed) {
		lastDepsBoxs[index] = deps;
		if (lastClearCallbacks[index]) {
			lastClearCallbacks[index]();
		}
		lastClearCallbacks[index] = callback();
	}
	index ++;
};
Copy the code

conclusion

  • With closures, the implementation of useState/useEffect is not esoteric
  • The neat thing is the way you organize multiple calls, the box.
  • Use hooks to avoid nesting if, for, and so on