❓ If you don’t already know, check out this article to see the differences and usages between three basic Hooks and traditional class components 😙

The three basic Hooks we refer to are:

  • useStateMaintenance within functional componentsstate
  • useEffectFunctional components have side effects called andcomponentDidMount,componentDidUpdateSimilar but different
  • useContextListen for changes to the provider

useState

UseState allows us to maintain state in functional components that traditionally would have required class components. For example, 🌰, we need an input box, and as the content of the input box changes, so does the content of the label label inside the component. Here are two different ways to write it:

Not using useState:

import React from "react";
/ / 1
export class ClassTest extends React.Component {
  / / 2
  state = {
    username: this.props.initialState
  }
  / / 3
  changeUserName(val) {
    this.setState({ username: val })
  }
  / / 4
  render() {
    return (
      <div>
        <label style={{ display: 'block'}}htmlFor="username">username: {this.state.username}</label>
        <input type="text" name="username" onChange={e= > this.changeUserName(e.target.value)} />
      </div>)}}Copy the code
  1. We need to define a class fromReact.Componentinherit
  2. We need to initialize one morestate
  3. Initialization changestateThe method of
  4. And the last thing I want to do is userenderThe function returnsJSX

✅ Use useState:

/ / 1
import React, { useState } from "react";

export function UseStateTest({ initialState }) {
  / / 2
  let [username, changeUserName] = useState(initialState)
  / / 3
  return (
    <div>
      <label style={{ display: 'block'}}htmlFor="username">username: {username}</label>
      <input type="text" name="username" onChange={e= > changeUserName(e.target.value)} />
    </div>)}Copy the code

Used in the parent component:

import React from "react";
// Import components
import { UseStateTest } from './components/UseStateTest'

/ / 4
const App = (a)= > (
  <div>
    <UseStateTest initialState={'initial value'} / >
  </div>
)

export default App;
Copy the code
  1. Need fromreactThe introduction ofuseStateThe 📦
  2. useuseStateMethod that receives an initialization parameter, definedstateVariables, and changesstateThe method of
  3. Use it directly where it is neededstateThis variable can be added to the event handler to trigger the changestateThe method of
  4. Called in the parent component, throughpropspassinitialStateThe initialization value

Replacing the class with the useState method not only improves performance, but you can also see a lot less code and no longer need to use this, so functional components that can maintain state are really nice 😀

  • class classTest extends React.Components {} 🔜 function UseStateTest(props) {}Functional component writing
  • this.state.username 🔜 usernameusestateDon’t needthis
  • this.setState({ username: '' }) 🔜 changeUserName('')changestateYou don’t have to writesetStatemethods

Documentation: https://zh-hans.reactjs.org/docs/hooks-state.html

useEffect

UseEffect is specifically designed to handle side effects, such as getting data, creating subscriptions, manually changing the DOM, and so on. You can imagine it’s a combination of componentDidMount and componentDidUpdate and componentWillUnmount.

For example 🌰🌰, let’s say we create a div tag that sends an HTTP request every time it is clicked and changes the page title to the corresponding value:

import React from 'react'
/ / 1
import { useState, useEffect } from 'react'

export function UseEffectTest() {
    let [msg, changeMsg] = useState('loading... ')
    / / 2
    async function getData(url) { // Get json data
        return await fetch(url).then(d= > d.json())
    }
    / / 3
    async function handleClick() { // Click the event to change state
        let data = await getData('https://httpbin.org/uuid').then(d= > d.uuid)
        changeMsg(data)
    }
    / / 4
    useEffect((a)= > { / / side effects
        document.title = msg
    })
    return (
        <div onClick={()= > handleClick()}>{msg}</div>)}Copy the code
  1. First of all, from thereactThe introduction ofuseEffect 😳
  2. Then create one that gets the datagetDatamethods
  3. Create an event handlerhandleClick
  4. useuseEffectDealing with side effects: changes to the pagetitle

If you use the traditional way of writing class components:

import React from 'react'
/ / 1
export class ClassTest extends React.Component {
    / / 2
    state = {
        msg: 'loading... '
    }
    / / 3
    async getData(url) { // Get json data
        return await fetch(url).then(d= > d.json())
    }
    handleClick = async() = > {// Click the event to change state
        let data = await this.getData('https://httpbin.org/uuid').then(d= > d.uuid)
        this.setState({ msg: data })
    }
    / / 4
    componentDidMount() {
        document.title = this.state.msg
    }
    componentDidUpdate() {
        document.title = this.state.msg
    }
    / / 5
    render() {
        return (
            <div onClick={this.handleClick}>{this.state.msg}</div>)}}Copy the code
  1. First create the classClassTest
  2. Initialize thestate
  3. Define methods for getting data and event handlers
  4. incomponentDidMountcomponentDidUpdatePhase changedocument.title
  5. At last,renderFunction to render

This pile of things to write people are asleep 💤

UseEffect not only removes some of the unnecessary stuff, but also incorporates the componentDidMount and componentDidUpdate methods, where the code only needs to be written once. 😀

This hook fires after the first rendering and every update, if you need to manually modify the custom trigger rules

See documentation: https://zh-hans.reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

In addition, the website also provides an example of subscribing to clear subscriptions:

Use useEffect to return a function directly:

The function returned is optional and may or may not be used:

Documents: https://zh-hans.reactjs.org/docs/hooks-effect.html#recap

For example, we use useEffect to unbind event handlers:

useEffect((a)= > {
    window.addEventListener('keydown', handleKeydown);
    return (a)= > {
        window.removeEventListener('keydown', handleKeydown); }})Copy the code

useContext

One of the biggest changes to useContext is that we don’t need to wrap Children around Consumer. For example, we create a context that has a state called username. And a method to modify username, handleChangeUsername

Create context

Not using useState:

This code does not use state hooks:

import React, { createContext } from 'react'

// 1. Create the context using createContext
export const UserContext = new createContext()

// 2. Create Provider
export class UserProvider extends React.Component {

    handleChangeUsername = (val) = > {
        this.setState({ username: val })
    }

    state = {
        username: ' '.handleChangeUsername: this.handleChangeUsername
    }

    render() {
        return (
            <UserContext.Provider value={this.state}>
                {this.props.children}
            </UserContext.Provider>Create Consumer export const UserConsumer = userContext.consumerCopy the code

Look what we did:

  1. First we usecreateContextCreate context
  2. And then we createProvider; It defineshandleChangeUsernameMethods andusernamestateAnd returns a packagethis.props.childrenProvider
  3. And then we’ll come backUserContext.Consumer

The code is verbose and can be simplified using useState, as mentioned above:

✅ Use useState:

Use state hooks:

import React, { createContext, useState } from 'react'

// 1. Create the context using createContext
export const UserContext = new createContext()

// 2. Create Provider
export const UserProvider = props= > {
    let [username, handleChangeUsername] = useState(' ')
    return (
        <UserContext.Provider value={{username, handleChangeUsername}} >
            {props.children}
        </UserContext.Provider>} // 3. Create Consumer export const UserConsumer = userContext.consumerCopy the code

Using useState to create context is much more concise.

Use context

Once the context is defined, let’s look at the difference between using useContext and not using useContext 🎁 :

Without useContext:

import React  from "react";
import { UserConsumer, UserProvider } from './UserContext'

const Pannel = (a)= > (
  <UserConsumer>} {({username, handleChangeUsername}) => (<div>
        <div>user: {username}</div>
        <input onChange={e= > handleChangeUsername(e.target.value)} />
      </div>
    )}
  </UserConsumer>
)

const Form = () => <Pannel></Pannel>

const App = () => (
  <div>
    <UserProvider>
      <Form></Form>
    </UserProvider>
  </div>
)

export default App;
Copy the code

✅ Using useContext:

Just import the UserContext and use the useContext method:

import React, { useContext }  from "react"; / / 1
import { UserProvider, UserContext } from './UserContext' / / 2

const Pannel = (a)= > {
  const { username, handleChangeUsername } = useContext(UserContext) / / 3
  return (
    <div>
      <div>user: {username}</div>
      <input onChange={e= > handleChangeUsername(e.target.value)} />
    </div>
  )
}

const Form = () => <Pannel></Pannel>

// 4
const App = () => (
  <div>
    <UserProvider>
      <Form></Form>
    </UserProvider>
  </div>
)

export default App;
Copy the code

Here’s what it does:

  1. So the first step is to introduceuseContext
  2. Then introduce theUserProviderAnd contextUserContext
  3. Call from the component you want to useuseContextMethods to obtainstate
  4. Of course, if used in the parent componentUserProviderNested masterchildren

This completes the refactoring with useContext and useState, and looks like a lot less code 😄

That’s it. Functional components that work with Hooks are really cool ⛄

Reference:

  • https://codeburst.io/quick-intro-to-react-hooks-6dd8ecb898ed
  • https://reactjs.org/docs/hooks-reference.html