preface

I want to say something else before I get to the point. As for componentization and modularization in the project, I believe that everyone is clear and understand why we do it. So, how many people understand the reuse of business logic

React hooks

concept

  • React has always advocated using function components, but sometimes when you need to use state or other functions, you have to use class components. Function components have no instances, no lifecycle functions, only class components
  • Before React 16.8,class components were called stateful and function components were stateless. After React 16.8, hooks were introduced to make function components stateful
  • Hooks are essentially a function that hooks state and lifecycle features into function components. React gives us some hooks, which we can also customize

The advantages of hooks

  • In the first place,hooks are popular partly because of the overuse of Class components, such as inheritance in Class and creating a new instance, which we don’t use at all
  • Reusing business logic code in components is difficult, but hooks can help (most importantly)
  • Hooks + function component development pattern, no this points to complex problems

The business scenario

After introducing hooks, I give you two custom hooks, from simple to difficult, to imagine the following business scenario

Simple Business Scenario 1- Get the mouse position

  • Scenario 1: The picture moves with the mouse

Business code

import React, { useState, useEffect } from 'react' import ReactDOM from 'react-dom' import Img from './logo192.png' export default function App () Const [position, setPosition] = useState({x: 0, y: 0) const [position, setPosition] = useState({x: 0, y: 0) 0}) useEffect(() => {const fn = (e) => {setPosition ({x: e.pagex, y: e.pageY }) } window.addEventListener('mousemove', Fn) / / component destroyed, remove the mouse events return () = > {window. The removeEventListener (' mousemove, fn)}}, []) return ( <div> <img src={Img} style={{ position: 'absolute', left: position.x, top: position.y }} /> </div> ) } ReactDOM.render(<App />, document.getElementById('root'))Copy the code
  • Scenario 2: The mouse position is displayed in real time

Business code

import React, { useState, useEffect } from 'react' import ReactDOM from 'react-dom' export default function App () { const [position, Const fn = (e) => {setPosition ({x: 0, y: 0}) useState({x: 0, y: 0}) useEffect(()) const fn = (e) => {setPosition ({x: 0}) e.pageX, y: e.pageY }) } window.addEventListener('mousemove', Fn) / / component destroyed, remove the mouse events return () = > {window. The removeEventListener (' mousemove, fn)}}, X}:{position.y} </div>)} reactdom.render (<App />, document.getelementbyId ('root'))Copy the code

As you will soon notice, the business code for these two scenarios is exactly the same. The need to reuse business logic comes when writing 77 business code all over again in a project to implement these two functions would make the project redundant and unmaintainable.

Analyze core business logic

Similarities:

  • Both need to be set to listen to the mouse movement event to obtain the mouse position

Difference:

  • Scenario 1 is to position the image
  • Scenario 2 is to get the mouse position

Custom hooks extract code

We can isolate the code that sets the listening events and gets the mouse position. Customize hooks to override the logicCopy the code

Note:

1. Customize hooks names beginning with use

Use only function components, class components, and hooks

Do not use if,for, etc.; do not write to events

  • Custom hooks code
import { useState, UseEffect} from 'react' // customize useMove hooks export default function useMove () {const [position, setposition] = useState({ x: 0, y: 0 }) useEffect(() => { const fn = (e) => { setposition({ x: e.pageX, y: E.pagey})} window.addeventListener ('mousemove', Fn) return () = > {/ / when the destruction of the component, clean up the mouse event window. The removeEventListener (' mousemove, fn)}}, []) return position}Copy the code

Import custom hooks to implement this function

Code after custom hooks are used in scenario 1

import React from 'react'
import ReactDOM from 'react-dom'
import Img from './logo192.png'
import useMove from './MouseMove'
export default function App () {
  const position = useMove()
  return (
    <div>
        <img src={Img} style={{ position: 'absolute', left: position.x, top: position.y }} />
    </div>
  )
}
ReactDOM.render(<App />, document.getElementById('root'))
Copy the code

Scenario 2: Code after using custom hooks:

import React from 'react' import useMove from './MouseMove' import ReactDOM from 'react-dom' export default function App () {const position = useMove() return (< div> print mouse position {position.x}:{position.y} </div>)} reactdom.render (<App />, document.getElementById('root'))Copy the code

The above scenario clearly shows the benefits of reusing business code, making our code significantly shorter, more maintainable and elegant. If you haven’t already seen the benefits of custom hooks reuse logic and feel that this business is too simple, then I will present another scenario

Complex Business Scenario 2- Countdown Case

  • Scenario 1: Click the button to count down, and the disable button will be removed when the countdown is over

Function code

import React, { useState, useEffect, useRef } from 'react' import ReactDOM from 'react-dom' export default function App () { const [cansend, setcansend] = useState(true) const [timer, Settimer] = useState(3) const time = useRef(null) // Click event const send = () => {// Initial assignment to 3 setTimer (3) // 1. Current = setInterval(() => {setTimer ((timer) => timer-1)}, 1000)} useEffect(() => {console.log(' current timer is ', timer) // If (timer === 0) {// 1. Setcansend (true) // 2. Clear timer clearInterval(time.current)}} [timer]) return ( <div> <input type="text" name="" id="" /> <button disabled={! cansend} onClick={send}>{cansend ? </button> </div>)} reactdom.render (<App />, document.getelementbyid ('root'))Copy the code
  • Scenario 2: The page starts the automatic countdown and jumps to the specified page after the countdown

Function code

import React, { useEffect, useRef, useState } from 'react' import ReactDOM from 'react-dom' export default function App () { const [n, Setn] = useState(5) const timeId = useRef(null) useEffect(() => {// Jump setn after 5 seconds (5) // Start timer timeid.current = setInterval(() => { setn((n) => n - 1) }, 1000) }, []) useEffect(() => {if (n === 0) {location.href = 'http://www.baidu.com' // Clear timer clearInterval(timeId.current) } }, <a href="http://www.baidu.com"> here </a> </div>)} reactdom.render (<App />, document.getElementById('root'))Copy the code
This scenario is a little more complex than the last one, so before we define the hooks, we need to understand what we are implementing and what is differentCopy the code

Analyze core business logic

Similarities:

  • It’s a countdown to the time to execute the callback

Difference:

  • Scenario 1 is triggered by a click, and Scenario 2 is triggered at the beginning
  • Unblock button when the time is up in scene 1, redirect page when the time is up in scene 2
  • The countdown time is different

Through the above analysis, the differences and similarities are obtained, and the ideas are as follows:

  1. User – defined countdown time and callback to execute after time 0, passed to hooks
  2. Custom hooks receive time and callback functions with parameters, with timer 0 executing the corresponding callback
  3. Custom hooks return the remaining time and timer startup mode to the user

Custom hooks implementation

Let’s create a new file useCountDown. Js where we can customize hooks

Import {useEffect, useRef, useState} from 'react' import {useEffect, useRef, useState} from 'react' callback = () => {}) => { const [count, Setcount] = useState(initCount) // Clear timer with useRef const timeID = useRef(null) // Set startup function const start = () => {// Set countdown time Timeid. current = setInterval(() => {setcount((count) => count -1)}, 100)} useEffect(() => {if (count === 0) {callback() // Clear timer clearInterval(timeid.current)}}, UseEffect (() => {return () => {clearInterval(timeid.current)}}, []) // Return the remaining time and start function return {count, start}}Copy the code

In the previous two scenarios, the logic code was reused

Scenario 1- Reuse logic

import React, { useState } from 'react' import ReactDOM from 'react-dom' import useCountdown from './useCountdown' export default function App () { const [cansend, setcansend] = useState(true) const { count, start } = useCountdown(3, () = > {/ / release button setcansend (true)}) const the send () = = > {/ / 1. Setcansend (false) start()} return (<div> <input type="text" name=" id="" /> <button disabled={! cansend} onClick={send}>{cansend ? </button> </div>)} reactdom.render (<App />, document.getelementbyid ('root'))Copy the code

Reuse logic before and after comparison

Scenario 2- After logic reuse

/* eslint-disable react-hooks/exhaustive-deps */ import React, { useEffect } from 'react' import ReactDOM from 'react-dom' import useCountdown from './useCountdown' export default function App () { const { count: n, start } = useCountdown(5, () => { location.href = 'http://www.baidu.com' }) useEffect(() => { start() }, []) return (< div > this page does not exist, {n} seconds will automatically return to < a href = "http://www.baidu.com" > here < / a > < / div >).} ReactDOM render (< App / >. document.getElementById('root'))Copy the code

Reuse logic before and after comparison

This is a slightly more complex example of the benefits of reuse logic

conclusion

From the above two scenarios, we can see the benefits of reusing logic, which is difficult to reuse without hooks. Some of you might say, well, in the first scenario above, I can do a custom function. What I’m trying to say is that implementations can be implemented, but functions don’t have a life cycle. In other words, you can no longer clear or remove events from the timer after you start the timer or start listening events. That’s very difficult for us to do. However, hooks bring life cycle and state concepts to function components, making front-end development simpler and easier to maintain

Mastering hooks and learning to reuse logic is the way to becoming an advanced front-end

  • The code word is not easy. Give it a thumbs up
  • Here I wish you see the annual salary million, touch fish every day