preface
I was recently asked by an interviewer: Can you implement a React Hooks program on Vue?
To be honest, the hardest part of this problem is how to make Vue and React render compatible. The worst part was that I was asked to write code on the spot. Luckily, my handwriting was so good that the interviewer was amazed. Yi? I seem to be bragging in the wrong place.
All right. I’m trying to tell you two things: don’t be a master on your resume. Otherwise, you are very likely to find yourself in the same situation as me. / Manual dog head
Write a set of Thoughts before React Hooks
So, how do you describe itReact Hooks
?
- Enhancements to functional components. Let functional components do what class components do.
- Let functional components store state
- Can have the ability to deal with side effects
- Let developers implement the same functionality without using class components
So, what’s the downside of class components? Class component deficiencies (React Hooks
Problems to be solved)
-
Lack of logical reuse mechanism
- In order to reuse the logic to add no actual rendering of the components, increase the nesting level of components, very bloated.
- The difficulty of debugging is increased and the efficiency of actual operation is reduced.
-
Class components can often become complex and difficult to maintain.
- Split a coherent set of business logic into multiple lifecycle functions
- There are multiple unwanted business logic in a lifecycle function.
- Class member methods are not guaranteed
this
Correctness of pointing - When we bind events to an element, when we want to change the state in an event handler, we usually need to change the state inside the function
this
Pointing is not as good asthis
Just point toundefined
. - The solution is
bind
Or the way functions are nested within functionsthis
Pointing to.
** What are the salient features of React Hooks? 支那
Feature points | React Hooks | Class |
---|---|---|
Usage scenarios | Inside the function | There’s no limit. You can write class anywhere, right |
Change the states | const [state,setState] = useState(initState) | this.setState |
The life cycle | Does not exist, but can be simulated by Effect Hooks | There are strict life cycle functions |
State storage | State Hooks | State variables are stored in this.state |
Status monitoring unit | State variables are units | Without this concept, monitor code can only be written in the lifecycle function |
UseState analysis and implementation
Start with the official useState chestnuts.
import React, { useState } from 'react';
function Example() {
// Declare a new state variable called "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()= > setCount(count + 1)}>
Click me
</button>
</div>
);
}
Copy the code
Well, if we change it again. For example:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable called "count"
const [count, setCount] = useState([0]);
const [name, setName] = useState('fat');
const [meizhi, setMeiZhi] = useState(() = >'bosses');
return (
<div>
<p>You clicked {count} times</p>
<p>Call me {name}</p>
<p>{name} is meizhi?</p>
<button onClick={()= >{ setCount([count[0] + 1]); SetName (' Fat man is a cheating and philandering man '); SetMeiZhi ((preMeizhi) = > ` ladies' ${preMeizhi} `); }}> Click me</button>
</div>
);
}
Copy the code
We can summarize the use of useState.
- Accepts incoming arguments of any type, which can be arrays, objects, functions, and so on.
- It can be called multiple times, each time deconstructing a different state variable.
setState
Can also bePass in the callback function. The change callback is automatically passed to the current corresponding state variable.- The structured state variables and the methods used to change them are bound 1-to-1.
- call
setState
After, to rerender
Function component
Start to write
// import React from 'react';
import ReactDOM from 'react-dom';
// Write render first, ready.
function render () {
ReactDOM.render(<App />.document.getElementById('root'));
}
// The App component is also ready
function App() {
const [count, setCount] = useState([0]);
const [name, setName] = useState('fat');
const [meizhi, setMeiZhi] = useState(() = >'bosses');
return (
<div>
<p>You clicked {count} times</p>
<p>Call me {name}</p>
<p>{name} is meizhi?</p>
<button onClick={()= >{ setCount([count[0] + 1]); SetName (' Fat man is a cheating and philandering man '); // setMeiZhi((preMeizhi)=> 'ladies ${preMeizhi}'); }}> Click me</button>
</div>
);
}
// Start with useState(...) start
let state;
function useState(initState) {
if(! state) state = initState;// If state is undefined, useState is called for the first time. The page has not been re-rendered
let setState = (newState) = > {
if(state ! == newState) { state = newState; } render() }return [state, setState]
}
Copy the code
Click on theClick me
before
Click on theClick me
after
The problem is obvious because there is only one state variable in the code, and each call to useState returns state. What we need to do is structure a different [state, setState] each time we call useState. Come again.
let state = []; // Store state variables
let setters = []; // The method to store the changed state variable
let stateIndex = 0; // Bind state[...] And setters [...]. That is, the state variable and the method to change it must have a 1-to-1 relationship.
function useState (initialState) {
state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState; / / in the same way. This is putting the state in an array.
setters.push(createSetter()); // Create a setState method based on the stateIndex and push it into the setters array.
let value = state[stateIndex]; // Take the value from an array of state variables
let setter = setters[stateIndex]; // Retrieve the corresponding setState from the setState method array
stateIndex++
return [value, setter]; // returns for the caller to deconstruct.
}
function createSetter () {
return (newState) = > {
state[stateIndex]= newState;
render();
};
}
Copy the code
Look at the result, it is:
Only the first row has changed. Only the value of the first state variable is rerendered. The stateIndex is already passed to the createSetter method in the code. Look carefully, and you’ll find a problem. When you call setState multiple times, the stateIndex is not retained.
This is solved with closures.
let state = []; // Store state variables
let setters = []; // The method to store the changed state variable
let stateIndex = 0; // Bind state[...] And setters [...]. That is, the state variable and the method to change it must have a 1-to-1 relationship.
function useState (initialState) {
state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState; / / in the same way. This is putting the state in an array.
setters.push(createSetter(stateIndex)); // Create a setState method based on the stateIndex and push it into the setters array.
let value = state[stateIndex]; // Take the value from an array of state variables
let setter = setters[stateIndex]; // Retrieve the corresponding setState from the setState method array
stateIndex++
return [value, setter]; // returns for the caller to deconstruct.
}
function createSetter (index) {
// Keep the index passed in by returning a new method. So here's the closure
return function (newState) { state[index] = newState; render (); }}Copy the code
And the results:
Use the useState and setState argument type function once more. The complete code is as follows:
let state = [];
let setters = [];
let stateIndex = 0;
const getStateByFn = (v, params) = > {
if (typeof v === 'function') {
const _newState = v(params);
if(! _newState)throw 'You must be return state'
return _newState
}
return v
}
function createSetter(index) {
return function (newState) { state[index] = getStateByFn(newState,state[index]) render(); }}function useState(initialState) {
state[stateIndex] = state[stateIndex] ? getStateByFn(state[stateIndex]) : getStateByFn(initialState);
setters.push(createSetter(stateIndex));
let value = state[stateIndex];
let setter = setters[stateIndex];
stateIndex++;
return [value, setter];
}
function render() {
stateIndex = 0;
ReactDOM.render(<App />.document.getElementById('root'));
}
function App() {
const [count, setCount] = useState([0]);
const [name, setName] = useState('fat');
const [meizhi, setMeiZhi] = useState(() = > 'bosses');
return (
<div>
<p>You clicked {count} times</p>
<p>Call me {name}</p>
<p>{name} is {meizhi}?</p>
<button onClick={()= >{ console.log('count:', count, 'name:', name, 'meizhi:', meizhi) setCount([count[0] + 1]); SetName (' Fat man is a cheating and philandering man '); SetMeiZhi ((preMeizhi) => 'dress ${preMeizhi}'); }}> Click me</button>
</div>
);
}
Copy the code
Click on theClick me
The results are as follows:
To be continued
It’s very detailed. If you have any questions, please leave a comment.
The implementation of useEffect will be explained in the next section.