1. About useState

  • What does useState do to get an array that can both read and write?
  • What happens when setN is executed? Does n change? Will App() be re-executed?
  • If App() is reexecuted, will the value of useState(0) be different each time?
function App() {
  const [n, setN] = useState(0);
  const [m, setM] = useState(0);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
      <p>{m}</p>
      <p>
        <button onClick={() => setM(m + 1)}>+1</button>
      </p>
    </div>
  );
}
Copy the code

Analysis:

  • setN
    • SetN must modify some data x, putting n+1 into that x
    • SetN must trigger rerendering
  • useState
    • UseState will definitely read the latest value of n from x
  • x
    • Each component has its own data x, which we’ll name state

2. Write useMyState as a simple alternative to useState

import React from "react";
import ReactDOM from "react-dom";
const rootElement = document.getElementById("root");
let _state;
const myUseState = (initState) => {
    _state = ( _state === undefined ? initState : _state);
    const setState = (newState) => {
        _state = newState
        render()
    }
    return [_state,setState]
}
const render = () => ReactDOM.render(<App />, rootElement);

function App() {
    const [n, setN] = myUseState(0);
    return (
        <div className="App">
            <p>{n}</p>
            <p>
                <button onClick={() => setN(n + 1)}>+1</button>
            </p>
        </div>
    );
}
ReactDOM.render(<App />, rootElement);
Copy the code
  • But such code also runs into problems. What if there is an M in addition to n?

3. Advanced version of useMyState method

import React from "react";
import ReactDOM from "react-dom";
const rootElement = document.getElementById("root");

let _state = [];
let index = 0;
const myUseState = (initState) => {
  let currentIndex = index;
  _state[currentIndex] = ( _state[currentIndex] === undefined ? initState : _state[currentIndex]);
  const setState = (newState) => {
    _state[currentIndex] = newState
    index = 0
    render()
  }
  index += 1
  return [_state[currentIndex],setState]
}
const render = () => ReactDOM.render(<App />, rootElement);

function App() {
  const [n, setN] = myUseState(0);
  const [m, setM] = myUseState(0);
  return (
    <div className="App">
      <p>{n}</p>
      <p>
        <button onClick={() => setN(n + 1)}>+1</button>
      </p>
      <p>{m}</p>
      <p>
        <button onClick={() => setM(m + 1)}>+1</button>
      </p>
    </div>
  );
}
Copy the code
  • Disadvantages of using the array method:
    • The order in which useState is called is very important
    • First render n on the first, M on the second, k on the third
    • The order of calls for the second rendering must be exactly the same
    • React does not allow if… else..
    • Example:
const [n, setN] = React.useState(0);
let m, setM;
if (n % 2 === 1) {
    [m, setM] = React.useState(0);
}
Copy the code

4. N

function App() {
    const [n, setN] = React.useState(0);
    const log() = = >setTimeout(() => console.log(`n: ${n}`), 3000);
    return (
        <div className="App">
            <p>{n}</p>
            <p>
                <button onClick={() => setN(n + 1)}>+1</button>
                <button onClick={log} >log</button> </p> </div> ); } // First click +1, then clicklog.logIs 1 // First clicklog, plus 1,logA value of 0Copy the code
  • Because every time useState renders the n in App(), it is a new N, that is, n=0 and n=1 coexist. After clicking log, the log produces the original n equal to 0, instead of the new N generated after +1.

5, useRef

function App() { const nRef = React.useRef(0); //nRef is an object {current:0} constlog() = = >setTimeout(() => console.log(`n: ${nRef.current}`), 1000);
    return (
        <div className="App">
            <p>{nRef.current}</p>
            <p>
                <button onClick={() => (nRef.current += 1)}>+1</button>
                <button onClick={log} >log</button>
            </p>
        </div>
    );
}
Copy the code
  • This solves the n clone problem, but there’s a new problem: the UI doesn’t update in real time, meaning useRef doesn’t trigger rendering
  • Solution: Add using useState to trigger updates (not recommended)
  • Example:
const nRef = React.useRef(0);
const update = React.useState()[1];
const log() = = >setTimeout(() => console.log(`n: ${nRef.current}`), 1000);
return (
    <div className="App"> < p > {nRef. Current} here and cannot be updated in real time < / p > < p > < button onClick = {() = > ((nRef. Current + = 1), update(nRef.current))}> +1 </button> <button onClick={log} >log</button>
        </p>
    </div>
);
Copy the code

6, summary

  • Each function component corresponds to a React node

  • Each node holds state and index

  • UseState reads state[index]

  • Index is determined by the order in which useState appears

  • SetState modifies state and triggers an update

  • Each time you render, the component function is executed again

  • All corresponding states have a doppelganger.

  • If you don’t want to have such a “split body” situation

  • You can use useRef/useContext, etc