current position:Home>Ten thousand words sum up react knowledge points to see if you can?
Ten thousand words sum up react knowledge points to see if you can?
2021-08-27 07:52:10 【Jiaxin cansiny】
This is my participation 8 The fourth of the yuegengwen challenge 3 God , Check out the activity details :8 Yuegengwen challenge
This article uses React Version is 17.0.2
, Non special declarations use functional components by default
️ Environmental preparation
We use official scaffolding create-react-app
To create our react application
First, make sure Node >= 10.16 and npm >= 5.6
node -v
npm -v
Copy code
And then execute
npx create-react-app react-demo
cd react-demo
npm start
Copy code
One React The project is created
JSX
JSX It's a JavaScript Grammar extension of , So that we can js Write in html、css...
const element = <h1>Hello, world!</h1>
Copy code
The above code is a simple JSX, We can also do that JSX Chinese expression , Use {}
The parcel
const element = <h1>Today is {new Date().toLocaleDateString()}</h1>
Copy code
JSX The notes in the are also required {}
, Of course, you can use it directly vscode Shortcut key Ctrl + /
{/* The right way to write notes */}
{ // The right way to write notes }
Copy code
JSX It's also an expression , in other words , You can if
Statement and for
Use... In cyclic code blocks JSX, take JSX Assign a value to a variable , hold JSX Pass in as a parameter , And return... From the function JSX
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>
}
return <h1>Hello, Stranger.</h1>
}
Copy code
In addition to JSX Write in html Labeled attribute when , To use Naming of small hump , for example ,JSX Inside class
Turned into className
,onclick
Turned into onClick
const element = <div className='classname'></div>
Copy code
When using inline styles , It's written in double brackets ( Use the little hump to write css style )
<h1 style={{ fontSize: "16px" }}>{count}</h1>
Copy code
JSX Tags can contain many sub elements , Use ()
The parcel
const element = (
<div> <h1>Hello!</h1> <h2>Good to see you here.</h2> </div>
)
Copy code
One more thing to note ,JSX The outermost layer of must have one and only one element , Otherwise, an error will be reported , You can also use it <React.Fragment></React.Fragment>
perhaps <></>
To make your outermost element empty
const element = (
<> <h1>Hello!</h1> <h2>Good to see you here.</h2> </>
)
Copy code
Last , Use ReactDOM.render()
Render element to root DOM In nodes
const element = <h1>Hello, world</h1>
ReactDOM.render(element, document.getElementById("root"))
Copy code
Conditions apply colours to a drawing
React Condition rendering and JavaScript The same as in China , Use JavaScript Operator if
perhaps Conditional operator
To create elements to represent the current state , And then let React Update... Based on them UI.
function UserGreeting(props) {
return <h1>Welcome back!</h1>
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn
if (isLoggedIn) {
return <UserGreeting />
}
return <GuestGreeting />
}
Copy code
You can also directly JSX Conditional operator in
For example, use the ternary operator condition ? true : false
function GuestGreeting(props) {
return <div>{props.isLoggedIn ? <UserGreeting /> : <GuestGreeting />}</div>
}
Copy code
Or use &&
function Mailbox(props) {
const unreadMessages = props.unreadMessages
return (
<div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2>You have {unreadMessages.length} unread messages.</h2>} </div>
)
}
Copy code
list & Key
A common scenario is that we need multiple duplicate components , Render data arrays by traversing them
below , We use Javascript Medium map()
Method to traverse numbers
Array . Turn each element in the array into <li>
label , Finally, we assign the resulting array to listItems
:
const numbers = [1, 2, 3, 4, 5]
const listItems = numbers.map(number => <li>{number}</li>)
Copy code
When we run this code , You will see a warning a key should be provided for list items
, It means when you create an element , Must include a special key
attribute .
Let's assign one to each list element key
Property to resolve the warning above :
const numbers = [1, 2, 3, 4, 5]
const listItems = numbers.map(number => <li key={number.toString()}>{number}</li>)
Copy code
key
In the above, we add a unique... To each list item according to the error information key, So this key What is it for ?
key help React Identify which elements have changed , Such as being added or deleted , Pay attention to this key Not for developers , But to react For your own use , You can't be in the component props Get in the key
Of an element key It's best that this element has a unique string in the list . Usually , We use... In the data id As an element key:
const todoItems = todos.map(todo => <li key={todo.id}>{todo.text}</li>)
Copy code
When the element is not certain id When , As a last resort, you can use the element index index As key:
const todoItems = todos.map((todo, index) => (
// Only do this if items have no stable IDs
<li key={index}>{todo.text}</li>
))
Copy code
If the order of the list items may change , It is not recommended to use an index as an index key value , Because this will lead to poor performance , It can also cause problems with component state .
One : use index As key The problems brought about by
In the example above , After adding elements to the array ,key The corresponding instances are not destroyed , It's a renewal . The specific update process we take key=0 To illustrate ,
- Component re render Get the new virtual dom
- New and old virtual dom Conduct diff, There are both new and old versions key=0 The components of ,react Think of the same component , Only components can be updated
- And then compare them children, Find that the text content of the content is different , and input The components don't change , This triggers the
componentWillReceiveProps
Method , To update the text content of its subcomponents - Because of the children in input The components don't change , It is also related to the data passed in by the parent component props There's no connection , therefore input Components don't update ( Namely its
componentWillReceiveProps
Method will not be executed ), Causes the value entered by the user not to change
Components
Components , Conceptually similar to JavaScript function . It accepts arbitrary input parameters ( namely “props”), And go back to the React Elements .
When do I need components ?
When we reuse a paragraph with a very similar structure JSX When , We should think of this paragraph JSX Pull apart into a separate component
The easiest way to define a component is to write JavaScript function :
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
Copy code
Or you can write a component as a separate jsx
file , Then introduce it in other files
Component naming must begin with uppercase , Otherwise it will be identified as html label , if html If there is no corresponding element with the same name, an error will be reported
When using components , Similar to a html Use it like a label
<div>
<Welcome name='Sara' />
<Welcome name='Cahal' />
<Welcome name='Edite' />
</div>
Copy code
When React When the element is a user-defined component , It will be JSX Received properties (attributes) And sub components (children) Conversion to a single object passed to the component , This object is called “props”.
props There's a special prop children
, That is, the child element of the package of the component
function FancyBorder(props) {
return <div className={"FancyBorder FancyBorder-" + props.color}>{props.children}</div>
}
function WelcomeDialog() {
return (
<FancyBorder color='blue'> <h1 className='Dialog-title'>Welcome</h1> <p className='Dialog-message'>Thank you for visiting our spacecraft!</p> </FancyBorder>
)
}
Copy code
It should be noted that props yes read-only Of , in other words , Component cannot modify its own props, Such a function is called “ Pure function ”, Because this function does not attempt to change the input parameter , And the same input parameter always returns the same result under multiple calls , There are no side effects .
in other words , We want to change props Can only be passed in props Time to change
Component communication
Use props , In fact, it completes the communication and value transfer between parent component and child component , But we want to change props When , If you change directly props Value , You will find that the page has not been re rendered , What's going on here ?
I have to introduce it React One provided by hook
,useState
We use useState
To write a counter component
import { useState } from "react"
function IncreaseButton() {
const [count, setCount] = useState(0)
return (
<> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </>
)
}
export default IncreaseButton
Copy code
In this component , First, I call useState
,useState
Will return a pair of values : At present State and a function that lets you update it , You can call this function in the event handler or somewhere else . When using this function to update state
after , Use this state
Of UI Will re render
useState
The only parameter is the initial state. In the example above , Our counter starts from zero , So initially state Namely 0
.
Father's son
I understand useState after , We'll know how to communicate between father and son
The parent component passes the parameters to be passed key={xxx}
Mode passed to sub components , Subcomponent pass this.props.key
To obtain parameters
If you need to change the of the incoming subcomponent props, You only need to use the variables passed to the child components useState
The parcel , Then you need to change props When , Use... In the parent component useState
Updates provided state Function update of state, The subcomponents will be re rendered
Son father
Father to son and son to father are very similar , It's also the use of useState
, One way is to , take useState
Simultaneous interpreting updates are provided to sub components. , Next, you can use this function in the child component to update the parent component state 了 .
Brother component communication
Communication between brothers is easier to think of , We can completely promote the state required between brother components to the parent component , Let parent component manage state, In this way, brother component communication can also be completed
Last , We can also use some state management tools to communicate between components , Common are Context Hook
、Redux
、dva
、mobx
wait
Event handling
- React The event was named after a small hump (camelCase), Not just lowercase .
- Use JSX Syntax, you need to pass in a function as an event handler , Instead of a string .
for example , Conventional HTML:
<button onclick="activateLasers()">Activate Lasers</button>
Copy code
stay React Slightly different in :
<button onClick={activateLasers}> Activate Lasers </button>
// Note that if your function needs to pass in parameters , It needs to be written like this
<button onClick={() => activateLasers(params)}> Activate Lasers </button>
// because {} The expression inside will execute immediately
Copy code
stay React Another difference is that you can't return by false
To prevent default behavior . You must use it explicitly preventDefault
. for example , Conventional HTML Block the default submission behavior of forms in , You could write it like this :
<form onsubmit="console.log('You clicked submit.'); return false">
<button type="submit">Submit</button>
</form>
Copy code
stay React in , It might look something like this :
function Form() {
function handleSubmit(e) {
e.preventDefault()
console.log("You clicked submit.")
}
return (
<form onSubmit={handleSubmit}> <button type='submit'>Submit</button> </form>
)
}
Copy code
Controlled components
stay HTML in , Form Elements ( Such as <input>
( It is an uncontrolled component )、 <textarea>
and <select>
) Usually maintain it yourself state, And update according to the user's input . And in the React in , Variable state (mutable state) Usually stored in the state Properties of the , And only by using setState()
To update .
We can combine the two , send React Of state Become “ Unique data source ”. Render the form's React Components also control what happens to the form during user input . By React The form input element that controls the value in this way is called “ Controlled components ”.
Setting up controlled components requires 3 A step :
- Definition preservation
input
The state of the value :const [value, setValue] = useState(")
. - Create an event handler , The event handler updates the state when the value changes :
const onChange = event => setValue(event.target.value);
Copy code
- by
input
Field assignment status value , And add event handlers :<input type="text" value={value} onChange={onChange} />
.
Here is a simple example
import { useState } from "react"
const MyInput = () => {
const [value, setValue] = useState("")
return (
<> <input value={value} type='text' onChange={e => setValue(e.target.value)} /> <p>{value}</p> </>
)
}
export default MyInput
Copy code
High order component HOC
Higher order components are components with parameters , Function whose return value is the new component
for example redux
Inside connect
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps)(TodoApp)
Copy code
Hook
When introducing components , We have learned useState
This hook, Next , Let's learn more about hook
Hook Are some that allow you to be in a function component “ Hook in ” React state And life cycle .Hook Can't be in class Used in components —— This makes you not use class Can also be used React.
️ There are two other points to note
- Can only be called on the outermost layer inside a function Hook, Don't cycle 、 Call in conditional judgement or subfunction
- Can only be invoked in functional components. Hook, Don't be in the other JavaScript Call in function
Reasons for restriction
The second point is easy to think of , But the first point is why ?
This is to ensure our Hooks Called in the same order in each render . This makes React Able to useState
and useEffect
Keep between calls hook Correct status .
With Preact Of Hook For example , It USES Arrays and Subscripts To achieve Hook Lookup (React Use the list , But the principle is similar )
// At present hook Global index of
let currentIndex
// Currently running components
let currentComponent
// First call currentIndex by 0
useState('first')
// Second call currentIndex by 1
useState('second')
Copy code
It can be seen that , Every time Hook All calls correspond to a global index Indexes , Use this index to the currently running component currentComponent
Upper _hooks
Find saved values in array , That is to say Hook Back to [state, useState]
So if the condition is called , Like the first one useState
Only 0.5 The probability of being called :
// At present hook Global index of
let currentIndex
// Currently running components
let currentComponent
// First call currentIndex by 0
if (Math.random() > 0.5) {
useState('first')
}
// Second call currentIndex by 1
useState('second')
Copy code
stay Preact When rendering components for the first time , hypothesis Math.random()
The random value returned is 0.6
, So the first one Hook Will be performed , The saved on the component _hooks
Status is :
_hooks: [
{ value: 'first', update: function }, { value: 'second', update: function }, ] Copy code
The search process is represented by a graph :
Suppose the second rendering ,Math.random()
The random value returned is 0.3
, There is only the second one useState Carried out , Then its corresponding global currentIndex
Would be 0, Go to at this time _hooks[0]
What I got in the book was first
The corresponding state , This will cause rendering confusion .
you 're right , Should have been second
Of value, Inexplicably pointed first
, Rendering is completely wrong !
Of course, we can think that since we look up in array order hook It could be wrong , Then we'll give everyone hook Specify a unique key
Well ? in fact React The team also considered adding one for each call key
Value design , But multiple flaws led to the rejection of the proposal , stay Why are sequential call pairs React Hooks Very important ? You can learn more about the reasons in .
useState
const [state, setState] = useState(initialState);
Copy code
Each rendering is a separate closure
- Every rendering has its own Props and State
- Each rendering has its own event handler
- When you click update status , Function components will be called again , Then each rendering is independent , The value obtained will not be affected by subsequent operations
function Counter2() {
let [number, setNumber] = useState(0)
function alertNumber() {
setTimeout(() => {
// alert Only the state when the button is clicked can be obtained
alert(number)
}, 3000)
}
return (
<> <p>{number}</p> <button onClick={() => setNumber(number + 1)}>+</button> <button onClick={alertNumber}>alertNumber</button> </>
)
}
Copy code
Functional update
If the new state Need to use the previous state calculated , Then you can pass the callback function as a parameter to setState. The callback function will receive the previous state, And return an updated value
function Counter() {
let [number, setNumber] = useState(0)
function lazy() {
setTimeout(() => {
// setNumber(number+1);
// In this way, it will be obtained every time it is executed state, Instead of using the click trigger state
setNumber(number => number + 1)
}, 3000)
}
return (
<> <p>{number}</p> <button onClick={() => setNumber(number + 1)}>+</button> <button onClick={lazy}>lazy</button> </>
)
}
Copy code
Initial value of inertia
useState The initial value of is inert , Works only when the component is first rendered . If state The initial value of needs to be obtained through complex calculation ,useState The initial value of can also be a function , The return value of the function will be useState The initial value of the .
function Counter5(props) {
console.log("Counter5 render")
// This function is executed only once during the initial rendering , When a component is re rendered with subsequent update status , This function will no longer be called
function getInitState() {
return { number: props.number }
}
let [counter, setCounter] = useState(getInitState)
return (
<> <p>{counter.number}</p> <button onClick={() => setCounter({ number: counter.number + 1 })}>+</button> <button onClick={() => setCounter(counter)}>setCounter</button> </>
)
}
Copy code
Do not pass in the same state
In the use of useState Of dispatchAction to update state When , Remember not to pass in the same state, This will keep the view from updating . For example, it's written below :
export default function Index(){
const [ state , dispatchState ] = useState({ name:'alien' })
const handleClick = ()=>{ // Click button , View not updated .
state.name = 'Alien'
dispatchState(state) // Direct change `state`, The address pointed to in memory is the same .
}
return <div> <span> { state.name }</span> <button onClick={ handleClick } >changeName++</button> </div>
}
Copy code
In the example above , When the button is clicked , The view was found unchanged , Why is this cause ?
stay useState Of dispatchAction In processing logic , It will be shallow twice state , Find out state identical , The update scheduling task will not be started ; demo Twice state Points to the same memory space , So the default is state equal , No view updates will occur .
resolvent : Put the above dispatchState Change to dispatchState({...state}) The problem has been fundamentally solved , Shallow copy object , Re requested a memory space .
setState Is it synchronous or asynchronous ?
About state There is another classic question , That's it setState yes “ Sync ” or “ asynchronous ” Of ?
We know Promise.then()
,setTimeout
It's asynchronous execution . from js In terms of execution , setState
It must be synchronous execution .
So synchronous and asynchronous are not discussed here setState
Whether to execute asynchronously , It's a call setState
after this.state
Can I update it now .
constructor(props) {
super(props);
this.state = {
data: 'data'
}
}
componentDidMount() {
this.setState({
data: 'did mount state'
})
console.log("did mount state ", this.state.data);
// did mount state data
setTimeout(() => {
this.setState({
data: 'setTimeout'
})
console.log("setTimeout ", this.state.data);
})
}
Copy code
And the output of this code , first console.log
Will be output data
, And the second one. console.log
Will be output setTimeout
. For the first time setState
When , It's asynchronous , The second time setState
When , It becomes synchronous again .
In the end setState
What is asynchronous and what is synchronous ? Why? ?
Say first conclusion
As long as you get in react
Scheduling process , That's asynchronous . As long as you don't get in react
Scheduling process , That's synchronous .
by React Event handler for control , And lifecycle function calls setState Updates will not be synchronized state . React Calls in events beyond control setState
It's synchronized . Like native events ,setTimeout/setInterval
etc. .
and setState
In the case of synchronous execution , DOM
Will also be updated synchronously , Which means that if you do it many times setState
, Will result in multiple updates , It's meaningless and a waste of performance . In the case of asynchronous execution, multiple state
Will be combined for batch update
But if you try on your own FC Of setTimeout
To call setState
after , Print state
, You'll find that he hasn't changed , Then you will be very confused , Why? ? Isn't this synchronous ?
This is because of a closure problem , You got the last one state
, The printed value is naturally the last one , This is the real time state
Has been changed .
From the perspective of source code ,setState Our behavior is “ asynchronous ” still “ Sync ” Depending on React perform setState Methods Execution context
(ExecutionContext).
If ExecutionContext
by NoContext
(0), Indicates that there are no other tasks currently in progress , be setState yes “ Sync ” Of .
if (
(executionContext & LegacyUnbatchedContext) !== NoContext &&
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
// .... Omit some code that will not be covered in this discussion
} else {
ensureRootIsScheduled(root, eventTime); // Trigger scheduler Dispatch ( Scheduling is asynchronous ) , Therefore, the function will not be triggered immediately render.
if (executionContext === NoContext) { // When the execution context is 0 when , The synchronization queue is refreshed
// .... Omit some code that will not be covered in this discussion
// Here's the key , Execute synchronous callback queue . Interested students can continue to view in the source code , It can be concluded that :
// if Outside the branch ensureRootIsScheduled(root, eventTime) And here flushSyncCallbackQueue()
// In the end, they call performSyncWorkOnRoot Conduct fiber Cyclic construction of tree
flushSyncCallbackQueue();
}
}
Copy code
Notice the Execution context
Not browser , In order to better control the rendering task , Avoid occupying the browser's main thread for a long time , React Achieve your own Execution context
.
Just bypass react Internal trigger change executionContext
The logic of , Can guarantee executionContext
It's empty , To realize setState
For synchronization .
The other thing to note is that
The above analysis is based on legacy
Pattern analysis , as everyone knows react the ( Probably ) To enter in full concurrent
Pattern ( You can refer to react Boot mode ). stay concurrent
In mode , This topic may be meaningless , Because from the latest code , stay concurrent
There is no judgment at all in mode executionContext
, therefore concurrent
In mode setState Are asynchronous
The first 18 topic :React in setState When is synchronization , When is asynchronous ? This issues The following is a detailed discussion
useEffect
useEffect(didUpdate);
Copy code
useEffect You can let us execute in a function component side effect operation . Event binding , Data request , Dynamic modification DOM.
useEffect Will be in every time React Execute... After rendering . Whether it's the first time you mount it , Or update .( Of course, we can control this behavior )
useEffect
Hook Can be seen as componentDidMount
,componentDidUpdate
and componentWillUnmount
The combination of these three life cycle functions .
That need not be removed effect
Such as sending network requests , Manual change DOM, Log , These are common operations that do not need to be cleared . Because after we do this , You can ignore them .
A simple example
import { useState, useEffect } from "react"
function Example() {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `You clicked ${count} times`
})
return (
<div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div>
)
}
Copy code
What needs to be removed effect
Like listening to events , Timers, etc
effect You can return a function , When react When clearing , Will execute the returned function . Every time I execute this effect when , They'll be right up to the last one effect Scavenging . It also performs cleanup when the component is uninstalled .
in other words , In the following code . Every update , Will be right about the last time effect To uninstall , And carry out this effect.
import { useEffect, useState } from "react"
function App() {
const [count, setCount] = useState(0)
useEffect(() => {
function handleClick() {
console.log("click body")
}
console.log(" Add event ")
document.body.addEventListener("click", handleClick)
return () => {
console.log(" Uninstall Events ")
document.body.removeEventListener("click", handleClick)
}
})
return (
<div className='App'> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}> to update </button> </div>
)
}
export default App
Copy code
effect performance optimization
Every time you execute effect, Clear the last effect Unnecessary performance waste may result . We can go through effect Second parameter of , control effect Implementation . The second parameter is useEffect Dependence , Only when dependencies change ,useEffect Will update .
import { useEffect, useState } from "react"
function App() {
const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
useEffect(() => {
console.log(" Initial rendering and count Execute on update ")
}, [count])
return (
<div className='App'> <h1>count:{count}</h1> <h1>num:{num}</h1> <button onClick={() => setCount(count + 1)}> to update count</button> <button onClick={() => setNum(num + 1)}> to update num</button> </div>
)
}
export default App
Copy code
When we pass an empty array as a dependency , Will tell React,effect Do not rely on any state perhaps props. We can use this behavior simulation componentDidMount
perhaps componentWillUnmount
. The most common application is in componentDidMount
Phase is used to send requests
import { useEffect, useState } from "react"
function App() {
const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
useEffect(() => {
console.log(" Called only when the component is mounted ")
}, [])
return (
<div className='App'> <h1>count:{count}</h1> <h1>num:{num}</h1> <button onClick={() => setCount(count + 1)}> to update count</button> <button onClick={() => setNum(num + 1)}> to update num</button> </div>
)
}
export default App
Copy code
How to be in useEffect Use in async/await?
async Function will return a by default Promise object , and useEffect in , Only return nothing or return a cleanup function . Console , The following warnings are triggered Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect..
The solution is as follows :
useEffect(() => {
const fetchData = async () => {
const response = await fetch("https://api.example.com/")
const data = await response.json()
setCount(data.length)
}
fetchData()
}, [])
Copy code
useContext
const value = useContext(MyContext);
Copy code
Receive one context object (React.createContext
The return value of ), And return to the current context Of value
value .useContext You can subscribe to context The change of . However, it still needs to be used by upper components <MyContext.Provider>
To provide the underlying components with context.
import { createContext, useContext, useState } from "react"
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee",
},
dark: {
foreground: "#ffffff",
background: "#222222",
},
}
const ThemeContext = createContext(themes.light)
function App() {
const [theme, setTheme] = useState(themes.dark)
return (
<> <ThemeContext.Provider value={theme}> <ThemedButton /> </ThemeContext.Provider> <ThemedButton /> <button onClick={() => { setTheme(themes.light) console.log("click") }} > change theme </button> </>
)
}
function ThemedButton() {
const theme = useContext(ThemeContext)
return (
<button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button>
)
}
export default App
Copy code
useReducer
useReducer Receive three parameters , Form like (state, action) => newState
Of reducer function ,initialArg Initial value ,init Inert initial value function . If three parameters are passed in ,init(initialArg) Use as initial value .
const [state, dispatch] = useReducer(reducer, initialArg, init)
Copy code
useReducer
and useState
Works in a similar way , but useReducer
In complex scenes useState
More suitable . for example state The logic is complex and contains multiple subvalues , Or next state Depend on the previous state etc. . also , Use useReducer
It can also optimize the performance of components that trigger deep updates , Because you can pass dispatch
Instead of callback functions
Here are the USES reducer Counter example for :
const initialState = { count: 0 }
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 }
case "decrement":
return { count: state.count - 1 }
default:
throw new Error()
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<> Count: {state.count} <button onClick={() => dispatch({ type: "decrement" })}>-</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> </>
)
}
Copy code
useCallback
useCallback Receive callback function and dependency array as parameters .useCallback Returns the memoized function . When dependencies change , Will return a new memoized function .
const memoizedCallback = useCallback(() => {
doSomething(a, b)
}, [a, b])
Copy code
useMemo
useMemo and useCallback similar .useMemo Returns the memoized value . When dependencies change , Will recalculate memoized value .
Feel similar vue
Calculation properties in
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
Copy code
useCallback(fn, deps)
amount to useMemo(() => fn, deps)
.
useRef
const refContainer = useRef(initialValue)
Copy code
useRef
Return to a variable ref object , Its .current
Property is initialized to the parameter passed in (initialValue
). Back to ref Objects remain the same throughout the life cycle of the component .
A common use case is imperative access to subcomponents :
function TextInputWithFocusButton() {
const inputEl = useRef(null)
const onButtonClick = () => {
// `current` The point has been mounted to DOM Text input elements on
inputEl.current.focus()
}
return (
<> <input ref={inputEl} type='text' /> <button onClick={onButtonClick}>Focus the input</button> </>
)
}
Copy code
useRef In addition to getting dom Outside the function of the node ,useRef Of current attribute , It is convenient to save any variable value .useRef Every time you render , Will return the same ref object .
We can use useRef
To save the timer timer, So that when the component is destroyed , Destroy timer correctly .
const timerRef = useRef()
const [count, setCount] = useState(0)
useEffect(() => {
timerRef.current = setInterval(() => {
setCount(pre => pre + 1)
}, 1000)
return () => {
timerRef.current && clearInterval(timerRef.current)
}
}, [])
Copy code
️ Customize Hook
- Customize Hook Must be use start
- Customize Hook Just logical reuse , Among them state It won't be shared .
- Customize Hook Other functions can be called internally Hook.
- Avoid premature splitting of abstract logic
Custom data acquisition Hook
We go through ajax When requesting cousin data , A lot of logic is universal . such as loading Processing of status , Processing of error messages , Page turning processing . We can abstract these logic into a public Hook. Different api, As custom Hook Parameters of .
Here is a data request customization Hook Example :
import { useEffect, useState } from "react"
function useDataApi(api) {
// the number of pages
const [page, setPage] = useState(1)
// loading state
const [loading, setLoading] = useState(false)
// error message
const [error, setError] = useState("")
// data
const [data, setData] = useState([])
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true)
setError("")
const result = await getData(api + page)
setData(result.data)
} catch (e) {
setError(e)
} finally {
setLoading(false)
}
}
fetchData()
}, [page])
return { loading, error, data, page, setPage }
}
export default useDataApi
Copy code
Life cycle
First, it shows that functional components do not have a real life cycle , Because the essence of function components is functions , No, state The concept of , Therefore, there is no life cycle theory , Just one render Function only .
But we can use useState
、 useEffect()
and useLayoutEffect()
To simulate the implementation lifecycle .
We can class Component declares some special methods , These methods are executed when the component is mounted or unloaded , These methods are called Life cycle approach
Each component contains “ Life cycle approach ”, You can override these methods , To facilitate the execution of these methods at specific stages of the run
class Life cycle of components
We can divide the life cycle into three stages :
- Mount stage
- Component update phase
- Unloading phase
-
mount
When a component instance is created and inserted DOM In the middle of the day , Its life cycle call sequence is as follows :
constructor()
: Constructors ( initialization ), Be careful not to props Copy the value of to statestatic getDerivedStateFromProps()
: fromprops
Get derived fromstate
, Used in place ofcomponentWillMount
render()
: Component mounting ,react The most important step , Create virtual dom, Conduct diff Algorithm , to update dom The trees are all herecomponentDidMount()
: The component is mounted
-
to update
When the components props or state Updates are triggered when changes occur . The order of component update lifecycle calls is as follows :
static getDerivedStateFromProps()
: coordinationcomponentDidUpdate
, You can overridecomponentWillReceiveProps
All uses ofshouldComponentUpdate()
: Determine whether to update the statusrender()
: Component mountinggetSnapshotBeforeUpdate
: obtain DOM Before updating SnapshotcomponentDidUpdate()
: Update complete
-
uninstall
componentWillUnmount
: Before component uninstall
You can go to ** Life cycle map ** Detailed view
constructor
stay mount Stage , The first function to execute , Used to instantiate React Components , If not initialized state Or no method binding , It doesn't need to be React Component implementation constructor .
constructor(props) {
super(props);
// Don't call here this.setState()
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
Copy code
getDerivedStateFromProps
trigger :state change 、props change 、forceUpdate
, Pictured above .
This is a static method , Is a and component itself " Unrelated " Role . In this static method , Except for two default location parameters nextProps and currentState outside , you cannot access
Data on any component .
// initialization / Call when updating
static getDerivedStateFromProps(nextProps, currentState) {
console.log(nextProps, currentState, "getDerivedStateFromProps Method execution ");
// The return value is for currentState A merger
return {
fatherText: nextProps.text,
};
}
Copy code
render
render()
The method is class The only method that must be implemented in a component , return JSX
Be careful : If shouldComponentUpdate()
return false, Will not call render()
componentDidMount
It is mainly used to do some operations when the component is loaded , For example, launching network requests or binding events . treat as vue Of mounted Just use it , What needs to be noted here is :
componentDidMount() Directly call setState(). It will trigger additional rendering , That's twice render, But it's not a big problem , The main thing is understanding .
shouldComponentUpdate
This method returns true
perhaps false
To determine if a new rendering needs to be triggered . Because rendering triggers the last level , So too. performance optimization
Where we have to fight . By adding judgment conditions to prevent unnecessary rendering . Be careful : First render
Or use forceUpdate()
This method will not be called when .
React The government has provided a general optimization scheme , That is to say PureComponent
.PureComponent The core principle is that it is implemented by default shouldComponentUpdate function , In this function, I'm going to props and state Conduct Shallow comparison
, Used to determine whether an update is triggered .
Of course PureComponent There is a shortcoming
Of , When you use it, you must pay attention to : Because of the shallow comparison , May be due to the deep data inconsistency caused by the wrong negative judgment , This results in the page No updates available
. Not suitable for use in the presence of Multiple nested objects
Of state and prop in .
shouldComponentUpdate(nextProps, nextState) {
// Shallow comparison only compares values and references , It's not true Object Compare the values of each item in
if (shadowEqual(nextProps, this.props) || shadowEqual(nextState, this.state) ) {
return true
}
return false
}
Copy code
getSnapshotBeforeUpdate
stay DOM Before updating
Called , The return value will be taken as componentDidUpdate()
The third parameter of , Otherwise undefined
componentDidUpdate
componentDidUpdate()
Will be called immediately after the update . The first rendering does not do this .
When the component is updated , You can do it here DOM To operate . If you are on the update before and after props Made a comparison , You can also choose to make a network request here .( for example , When props When there is no change , The network request will not be executed ).
componentDidUpdate(prevProps) {
// characteristic use ( Don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
Copy code
You can also be in componentDidUpdate()
in Call directly setState()
, But please pay attention to It has to be wrapped in a conditional statement , Deal with it as in the example above , Otherwise, it will lead to a dead cycle .
componentWillUnmount
componentWillUnmount()
It will be called directly before the component is unloaded and destroyed . Perform the necessary cleanup operations in this method , for example , eliminate timer, Cancel network request or clear in componentDidMount()
Subscriptions created in, etc .
Error handling
There are also two life cycles for error handling
static getDerivedStateFromError()
componentDidCatch()
Simulating life cycles in functional components
-
constructor
: Function components do not need constructors , We can do it by callinguseState
To initialize the state. If the cost of calculation is more expensive , You can also pass a function touseState
.const [num, UpdateNum] = useState(0) Copy code
-
getDerivedStateFromProps
: In general , We don't need to use it , We can do it in Update during rendering state, To achievegetDerivedStateFromProps
Purpose .function ScrollView({row}) { let [isScrollingDown, setIsScrollingDown] = useState(false); let [prevRow, setPrevRow] = useState(null); if (row !== prevRow) { // Row Has changed since the last rendering . to update isScrollingDown. setIsScrollingDown(prevRow !== null && row > prevRow); setPrevRow(row); } return `Scrolling down: ${isScrollingDown}`; } Copy code
React Will immediately exit the first rendering and use the updated state Rerun components to avoid consuming too much performance .
-
shouldComponentUpdate
: It can be usedReact.memo
Wrap a component to itsprops
Make a shallow comparisonconst Button = React.memo(props => { // Specific components }) Copy code
Be careful :
React.memo
Equivalent toPureComponent
, It's only shallow props. It can also be used hereuseMemo
Optimize every node . -
render
: This is the function component body itself . -
componentDidMount
,componentDidUpdate
:useLayoutEffect
It's the same call phase as both of them . however , I recommend you use it firstuseEffect
, Only try to use it when it goes wronguseLayoutEffect
.useEffect
Can express all these combinations .// componentDidMount useEffect(() => { // Need to be in componentDidMount What to do }, []) useEffect(() => { // stay componentDidMount, as well as count When changes componentDidUpdate What to do document.title = `You clicked ${count} times` return () => { // Need to be in count When changes componentDidUpdate( Precede document.title = ... perform , Comply with clean before update ) // as well as componentWillUnmount What to do } // When the function of Cleanup Functions are executed in the order defined in the code , It has nothing to do with the properties of the function itself }, [count]) // Only in count Update on change Copy code
-
componentWillUnmount
: amount touseEffect
Back insidecleanup
function// componentDidMount/componentWillUnmount useEffect(() => { // Need to be in componentDidMount What to do return function cleanup() { // Need to be in componentWillUnmount What to do } }, []) Copy code
-
componentDidCatch
andgetDerivedStateFromError
: at present Not yet These methods Hook Equivalent writing , But soon it will add .
For the convenience of memory , It is summarized in the following table .
class Components | Hooks Components |
---|---|
constructor | useState |
getDerivedStateFromProps | useState Back to update function |
shouldComponentUpdate | useMemo |
render | The function itself |
componentDidMount | useEffect |
componentDidUpdate | useEffect |
componentWillUnmount | useEffect The function returned in |
componentDidCatch | nothing |
getDerivedStateFromError | nothing |
The execution order of multiple components
Father son component
-
Mount stage
branch Two Stage :
- The first One Stage , From the parent component to its own
render
, Analyze which sub components need to be rendered , And to them Sub components of synchronization Create , Press Recursion sequence Execute sub components one by one torender
, Generated to the parent-child component Virtual DOM Trees , and commit To DOM. - The first Two Stage , here DOM The node has been generated , Component mount complete , Start the follow-up process . First, trigger the synchronization sub components in turn
componentDidMount
, Finally trigger the .
Be careful : If the parent component contains a different child component , It will be created after the parent component is mounted .
So the order of execution is :
Parent component getDerivedStateFromProps —> Synchronize subcomponents getDerivedStateFromProps —> Synchronize subcomponents componentDidMount —> Parent component componentDidMount —> Step sub assembly getDerivedStateFromProps —> Step sub assembly componentDidMount
- The first One Stage , From the parent component to its own
-
Update phase
React The design follows a one-way data flow model , in other words , Data flows from the parent component to the child component .
-
The first One Stage , Start with the parent component , perform
static getDerivedStateFromProps
shouldComponentUpdate
Update to your
render
, Analyze which sub components need to be rendered , Also on Child components Create , Press Recursion sequence Execute sub components one by one torender
, Generated to the parent-child component Virtual DOM Trees , And with the existing Virtual DOM Trees Compare , To calculate the Virtual DOM The real part of change , And only for this part of the original DOM operation . -
The first Two Stage , here DOM The node has been generated , Component mount complete , Start the follow-up process . First, trigger the following functions of the synchronization subcomponent , Finally trigger the .
getSnapshotBeforeUpdate()
componentDidUpdate()
React These functions are executed in the order above , Each function is the first execution of each subcomponent , Then there is the execution of the parent component .
So the order of execution is :
Parent component getDerivedStateFromProps —> Parent component shouldComponentUpdate —> Child components getDerivedStateFromProps —> Child components shouldComponentUpdate —> Child components getSnapshotBeforeUpdate —> Parent component getSnapshotBeforeUpdate —> Child components componentDidUpdate —> Parent component componentDidUpdate
-
-
Unloading phase
componentWillUnmount()
, In sequence The first execution of the parent component , The subcomponents are as follows JSX The order defined in executes the respective methods in turn .Be careful : If you uninstall an old component with the creation of a new component , The new component will be created and executed first
render
, Then uninstall the old components you don't need , Finally, the new component performs the callback after the mount .
Brother components
-
Mount stage
If it's a synchronous route , The order in which they are created and defined in the common parent component is Agreement Of .
If it's an asynchronous route , The order in which they were created and js Loading is done in the same order .
-
Update phase 、 Unloading phase
The communication between sibling nodes is mainly through the parent component (Redux and Context Also passed down by changing the parent component
props
Realized ), Satisfy React The design follows a one-way data flow model , So communication between any two components , In essence, it can be attributed to the update of parent-child components .therefore , Brother component update 、 Unloading phase , Please refer to Father son component .
route
When we write a project , There may not be only one page , At this time, you need to introduce routing , The following describes the commonly used react-router
Install dependencies first
npm install react-router-dom
yarn add react-router-dom
Copy code
Routing jump
Route jumps can be used Link
Or is it NavLink
Components
import {Link, NavLink} from "react-router";
<Link activeClassName="nav-active" className="nav" to="/about">About</Link>
<NavLink activeClassName="nav-active" className="nav" to="/home">Home</NavLink>
Copy code
activeClassName
: On the current route , The corresponding component will automatically add the classclassName
: Current component class nameto
: The route corresponding to the current component
Link
Components and NavLink
All components can perform route jump , The difference lies in : Corresponding to the current route NavLink
It will automatically add class
: active
, and Link
Can't .
You can also use useHistory
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}> Go home </button>
);
}
Copy code
Registered routing
import {Route} from "react-router";
<Route path="/home" component={Home}></Route>
<Route exact path="/about" component={About}></Route>
Copy code
path
: The route to be monitoredcomponent
: The component that the route is bound to ( Or put the components directly in theRoute
Child elements )exact
: Optional , When not writtenfalse
, Whether to choose strict matching
When the current route corresponds to the route bound by the routing component , The bound component is displayed .
Routing strict matching and fuzzy matching
Routing is more than just one level , Sometimes there are multiple levels of nesting , such as :
http://localhost:3000/home/a/b/c
Copy code
Fuzzy matching : If the current route is equal to or contains ( Attention hierarchy ) The situation of , Then enable the component
http://localhost:3000/home/a/b/c
Contains the route/home
http://localhost:3000/a/b/home/c
No route is included/home
( The hierarchy is wrong )
Strictly match : If the current route is equal to the matching route , To enable the component
http://localhost:3000/home
And routing/home
equalhttp://localhost:3000/home/a
And routing/home
It's not equal
Redirection Route
When the user enters a route without , After that, we need to redirect the page to an existing page
At this time, we need <Redirect />
import {Redirect, Route} from "react-router";
<Route ....../>
<Route ....../>
<Redirect to="/home"/>
Copy code
to
: Which route to redirect to
Redirect
Need to be placed in all Route
below , When the above Route
When it doesn't match , Then the route will be redirected to the specified route .
Switch route
Use Switch
The components wrap all the Route
and Redirect
, When multiple matching routes appear , Only the first matching component is rendered .
import {Switch, Route, Redirect} from "react-router";
<Switch> <Route ..../> <Route ..../> <Redirect to="..."/> </Switch>
Copy code
Router
You want to use the routing jump component and the routing component , There's one router component left , At the same time, the router component must contain these two components .
Generally in order to make the whole React application You can use routing components , So we usually wrap the router on the root component .
import {HashRouter, BrowserRouter} from "react-router";
ReactDOM.render(
<HashRouter> <App/> </HashRouter>,
document.querySelector("#root")
);
Copy code
There are two kinds of router components , Namely HashRouter
And BrowserRouter
( namely vue Medium history
Pattern ), They correspond to two routing methods respectively .
The difference between the two HashRouter
Mode of url Finally, there is one #
Number , and BrowserRouter
No,
Usually use HashRouter
, Because it's the simplest , Server side rendering is not required
Parameter passing in routing
params
<Route path="/home/message/detail/:id" component={Child} />
Copy code
:id
representative id
Is a variable parameter
Subcomponent pass useParams
obtain
const { id } = useParams();
Copy code
search
<Route path="/home/message/detail/?id='xxx'" component={Child} />
Copy code
react-router
No resolution provided search
Parametric api, We need to analyze it ourselves
utilize qs
library
const {id} = qs.parse(this.props.location.search);
Copy code
State management
Context Hooks
utilize context + reducer The implementation is similar to redux State management , But there are some performance problems that we need to optimize ourselves
redux
Well-known JavaScript State Management Library , also react-redux
, Make in react Use in redux Become more convenient
dva
mobx
Reference article
react-router Official documents
Hooks And React Life cycle relationships
「 Learning notes 」ReactHooks introduction
I broke it React Hook Must be in order 、 Shackles that cannot be invoked in conditional statements
copyright notice
author[Jiaxin cansiny],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827075009249u.html
The sidebar is recommended
- Crazy blessing! Tencent boss's "million JVM learning notes", real topic of Huawei Java interview 2020-2021
- JS JavaScript how to get the subscript of a value in the array
- How to implement injection in vuex source code?
- JQuery operation select (value, setting, selected)
- One line of code teaches you how to advertise on Tanabata Valentine's Day - Animation 3D photo album (music + text) HTML + CSS + JavaScript
- An article disassembles the pyramid architecture behind the gamefi outbreak
- BEM - a front-end CSS naming methodology
- [vue3] encapsulate custom global plug-ins
- Error using swiper plug-in in Vue
- Another ruthless character fell by 40000, which was "more beautiful" than Passat and maiteng, and didn't lose BMW
guess what you like
-
Huang Lei basks in Zhang Yixing's album, and the relationship between teachers and apprentices is no less than that in the past. Netizens envy Huang Lei
-
He was cheated by Wang Xiaofei and Li Chengxuan successively. Is an Yixuan a blessed daughter and not a blessed home?
-
Zhou Shen sang the theme song of the film "summer friends and sunny days" in mainland China. Netizen: endless aftertaste
-
Pink is Wangyuan online! Back to the peak! The new hairstyle is creamy and sassy
-
Front end interview daily 3 + 1 - day 858
-
Spring Webflux tutorial: how to build reactive web applications
-
[golang] walk into go language lesson 24 TCP high-level operation
-
August 23, 2021 Daily: less than three years after its establishment, Google dissolved the health department
-
The female doctor of Southeast University is no less beautiful than the female star. She has been married four times, and her personal experience has been controversial
-
There are many potential safety hazards in Chinese restaurant. The top of the program recording shed collapses, and the artist will fall down if he is careless
Random recommended
- Anti Mafia storm: He Yun's helpless son, Sun Xing, is destined to be caught by his dry son
- Introduction to flex flexible layout in CSS -- learning notes
- CSS learning notes - Flex layout (Ruan Yifeng tutorial summary)
- Today, let's talk about the arrow function of ES6
- Some thoughts on small program development
- Talk about mobile terminal adaptation
- Unwilling to cooperate with Wang Yibo again, Zhao Liying's fans went on a collective strike and made a public apology in less than a day
- JS function scope, closure, let, const
- Zheng Shuang's 30th birthday is deserted. Chen Jia has been sending blessings for ten years. Is it really just forgetting to make friends?
- Unveil the mystery of ascension
- Asynchronous solution async await
- Analysis and expansion of Vue infinite scroll source code
- Compression webpack plugin first screen loading optimization
- Specific usage of vue3 video play plug-in
- "The story of huiyeji" -- people are always greedy, and fairies should be spotless!
- Installing Vue devtool for chrome and Firefox
- Basic usage of JS object
- 1. JavaScript variable promotion mechanism
- Two easy-to-use animation JS that make the page move
- Front end Engineering - scaffold
- Java SQL Server intelligent fixed asset management, back end + front end + mobile end
- Mediator pattern of JavaScript Design Pattern
- Array de duplication problem solution - Nan recognition problem
- New choice for app development: building mobile applications using Vue native
- New gs8 Chengdu auto show announces interior Toyota technology blessing
- Vieira officially terminated his contract and left the team. The national security club sent blessings to him
- Less than 200000 to buy a Ford RV? 2.0T gasoline / diesel power, horizontal bed / longitudinal bed layout can be selected
- How does "heart 4" come to an end? Pinhole was boycotted by the brand, Ma Dong deleted the bad comments, and no one blessed him
- We are fearless in epidemic prevention and control -- pay tribute to the front-line workers of epidemic prevention!
- Front end, netty framework tutorial
- Xiaomi 11 | miui12.5 | android11 solves the problem that the httpcanary certificate cannot be installed
- The wireless charging of SAIC Roewe rx5 plus is so easy to use!
- Upload and preview pictures with JavaScript, and summarize the most complete mybatis core configuration file
- [25] typescript
- CSS transform Complete Guide (Second Edition) flight.archives 007
- Ajax foundation - HTTP foundation of interview essential knowledge
- Cloud lesson | explain in detail how Huawei cloud exclusive load balancing charges
- Decorator pattern of JavaScript Design Pattern
- [JS] 10. Closure application (loop processing)
- Left hand IRR, right hand NPV, master the password of getting rich