The author of this article Ruoduan. Cn please note the source

  • origin

    I am fully responsible for the background management of IM instant chat, a new project of the company in the middle desk system. The front-end technology selection Want to use the relatively new is hot technology – reactHook + react – Router5 + Typescript + (mobx | useContext + useState), as for the brackets later answer, Personally, I think it can replace mobx and Redux state management to some extent

  • This article will cover Typescript, react-hook, and reacthook-tsx (practices)

    • Typescript

      • Project structures,
      • The type definition
      • Application analysis
      • .
    • The React – Hook ⭐ ️

      • useState
      • useEffect
      • useContext
      • .
    • Hook and Mobx redux, etc., to achieve their own state management

    • The React family don’t explain the stuff in detail.


All right, let’s get started

Typescript

React-typescript project scaffolding

The NodeJS environment requires a Not download link

We used the scaffolding create-react-app to build the React-typescript project environment directly

The version must be nodeJS 8+ and Yarn 0.25+

npx create-react-app my-app --typescript

npm init react-app my-app --typescript

yarn create react-app my-app --typescript
Copy the code

Typescript project files

  • Here’s a look at some of typescript’s file definitions
./ / SRC./ React-app-env.d. ts // Global declaration tsconfig.json // typescript configuration fileCopy the code

Tsconfig. json: 🌰

{
  "compilerOptions": {
      "experimentalDecorators": true."target": "es5", // Language compilation target"lib": [
      "dom"."dom.iterable"."esnext"]."allowJs": true."skipLibCheck": true."esModuleInterop": true."allowSyntheticDefaultImports": true."strict": true."forceConsistentCasingInFileNames": true."module": "esnext"."moduleResolution": "node"."resolveJsonModule": true."isolatedModules": true."noEmit": true."jsx": "react"// Component syntax environment},"include": [// compile the target directory"src"]},Copy the code
  • React-app-env.d. ts is the TypeScript declaration file 🌰 for example: you introducedjQueryIn the typescript:
$('#dom');
// or
jQuery('#dom');
Copy the code

// ERROR: Cannot find name ‘jQuery’. Error because ts compiler does not know $() or jQuery

We need to define this variable globally with the declare modifier 🌰

declare var jQuery: (selector: string) = > any;

jQuery('#foo');
Copy the code

So we can have fun using jquery

But predecessors trees descendants cool a lot of library community has given me the definition of our installation can be

yarn add @types/jquery --save-dev

We will also use the @types type installation in later projects

You can search TypeSearch for the library type you want

Now that we’ve gotten a first look at Typescript’s project structure, it’s a superset of JS, a progressive language, as stated on the Typescript website. It’s compatible with most of the new syntax in JS and adds types to it

Install antD, React-Router-DOM,…

Yarn add ANTd React-router-dom: 🌰

Note: ⚠️ : react-router-dom needs to install @types oh yarn add @types/react-router-dom –save-dev

Antd Engineering reference

Below let me enter the key ~

React-hook

As we know, React is divided into two components, one is class component, the other is function component

The difference between

The difference between class func
Define the way class func
state There are (state) There is no
this There are There is no
The statement period There are There is no
terseness ordinary A more concise

By comparison, we can see that traditional function components have no state and lifecycle

So in previous development, functional components were often used as a supplement to simple components

React-hook allows us to use state component state management in functional components. It also enables us to realize the declaration cycle — side effects. In addition, it greatly simplifies the code, making it more concise and easy to understand

userState

Let’s look at the following two pieces of code

import React, { useState } from 'react';

function Example() {
  // Declare a 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

Is equivalent to

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>); }}Copy the code
  • You can see we’re importinguseStateUse the array destructor syntax to define two variablescount, setCountIt passes in an initial value of 0, and in the following usage we get rid of the nastythisDirectly available
  • Conut is our hook variable equal tostate
  • SetCount is what we’re looking atcountThe assignment function of theta is equal tothis.setState()

Effect Hook

Effect Hooks allow you to perform side effects in function components

Look at the code below

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Update the page title in the component
  useEffect((a)= > {
    // Set the page title
    document.title = ` digital${count} `;
  });

  return (
    <div>
      <p>Digital {count}</p>
      <button onClick={()= > setCount(count + 1)}>
        + 1
      </button>
    </div>
  );
}
Copy the code

Equivalent to the class

lass Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = ` digitalThe ${this.state.count} `;
  }

  componentDidUpdate() {
    document.title = ` digitalThe ${this.state.count} `;
  }

  render() {
    return (
      <div>
        <p>Digital {this. State. The count}</p>
        <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
          + 1
        </button>
      </div>); }}Copy the code

We can see the difference in the class component componentDidUpdate we repeat the definition of the life cycle, componentDidMount

  • Why do we use the data in class state?

    • We know that the data defined in state in the class component is going to be rerendered after the data is updated

    • UseEffect calls it after the DOM update has been performed. In this effect, we set the title property of the document, but we can also perform data fetching or call other imperative apis.

    • Note ⚠️ : By default, it is executed after the first render and after each update. (We’ll talk about how to control it later.)

    What useEffect does is it simply tells the React component that it needs to do something after rendering, and then it does it after each rendering

    Let’s introduce the useEffect implementation for componentDidMount and componentDidUpdate

    First of all, we can define multiple Usestates and UseEffects in our function component and they will execute in sequence

    The return value of useEffect written earlier determines the type and destruction of this side effect

    • Return function: encountered a side effect of clearing
    • Return [] Empty array: Effect that runs only once (only when the component is mounted and unmounted)
    • Avoid infinite loops

    UseEffect = = = componentDidMount 🌰

    For example, we want to request data and render it to the page when the page is mounted

    let [list, setList] = useEffect([])
    
    // Get the data
    const getList = async() = > {let res = await axios('xxx')}// Mount side effects only once
    useEffect((a)= > {
        getList()
    }, [])
    
    Copy the code

    UseEffect = = = componentDidUpdate 🌰

    Again, we need to update the mobx subscribed store data to the page in real time

     let [list, setList] = useEffect([])
     let [data, setData] = useEffect(store.rows)
     
     // Get the data
     const getList = async() = > {let res = await axios('xxx')}// Obtain the data in the store
     const getStore = (a)= > {
         @observer
         letres = store.getxxxxx ... SetData (res)}// Mount side effects only once
     useEffect((a)= > {
         getList()
     }, [])
     
     // Side effect functions to be cleared
     useEffect((a)= > 
         ((a)= >
             getStore
         )()
     )
     
    Copy the code

    So far we have basically understood the basic use of reactHook. Here is a simple Redux state management based on Reacthook-usecontext

    Other ReactHook implements basicRedux

    Based on the previous useReducer, and createContext, useContext

    Let’s take a look at the additional Hook useReducer:

    const [state, dispatch] = useReducer(reducer, initialArg, init);
    Copy the code

    It receives a Reducer of the form (state, action) => newState and returns the current state and its corresponding dispatch method. (Not a bit familiar, used redux children’s shoes ~)

import * as React from 'react'
const { useContext, useReducer, createContext } = React

// Return the state according to action.reduce
function reducerInAction(state, action) {
    if (typeof action.reducer == 'function') {
        return action.reducer(state)
    }
    return state
}
// Process store data
export default function createStore(params) {
    const{ _State = {}, reducer } = { ... params,reducer: reducerInAction
    }
    
    // Status management data is distributed by createContext
    const Appcontext = createContext()
    
    const upReducer = (lastState, action) = > {
        // Update the data
        let netxState = reducer(lastState, action)
        store._state = netxState
        return netxState
    }
    const store = {
        _state: _State,
        dispatch: undefined.getState: (a)= > {
            return store._state
        },
        useContext: (a)= > {
            return useContext(Appcontext)
        }
    }
    // Return the data after processing
    const Provider = props= > {
        const [state, dispatch] = useReducer(upReducer, _State)
        if(! store.dispatch) { store.dispatch =async (action) => {
                if (typeof action === 'function') {
                    await action(dispatch, store.getState())
                } else {
                    dispatch(action)
                }
 
            }
        }
        return <Appcontext.Provider {. props} value={state} />
    }
 
    return {
        Provider,
        store
    }
}
Copy the code

Use ⬆ ️

import * as React from 'react'
import HooksRedux from '@/HooksRedux'
const {
    Provider,
    store
} = _HooksRedux({
    State: { name: 'Ming'.age: '18' }
    
/ / request
const Add_action = (a)= > {
    return {
        type: 'ADD',
        reducer(state) {
            return {
                ...state,
                age: state.age + 1}}}Copy the code

@Reference

Ps: That’s basic of Redux, but IN my actual projects I still use MOBx, and its design patterns and object-oriented writing are more comfortable. May refer to


Practice (TSX + Hook)

– I can’t decideAny– anyscript

Ps: This is certainly not desirable, but in our rapid development process we sometimes have a generic | interface that is uncertain. We can use any for a while and then change later

  • Chestnut 🌰

For example, if we want to pass an object to a child component using props, but the object is the interface data, and we’re not sure what the data types and properties of the object are, we can use any for now, and I usually Type TODO any Type in there for later processing.

– React.FC

We can see code like this:

const app: React.FC = () => {
    ...
}
Copy the code

FC = Functional Component SFC = Stateless Functional Component

Type Type react.fc

= react.function.component

Sometimes it’s ok if you don’t, but the suggestion is to add it so you can tell Typescript about your function components

– jsDoc and interface

JsDoc is a plugin for adding formatting comments to func in the editor | IDE. It’s important to use the powerful VSCode Interface in Typescript. It describes my interfaces, objects…

The thing to note here is that jsDoc! == interface

  1. Mandatory => “:” The colon-marked attributes must exist. They cannot be more or less
  2. Optional attributes => “? “Optional” means optional
  3. Read-only attribute => “readonly” :
  4. Any attribute [propName: type] : any indicates that any attribute is defined as a string value

Interface is well written to make our code robust

– Generic and type

Take the following code for example

let _userList: Array<object> = []
let [userList, setUserList] = useState(_userList)

let _userList: object[] = []
let [userList, setUserList] = useState(_userList)
Copy the code

You can use either method, but don’t make them ===

Generics have even more powerful uses

function createArray<T> (length: number, value: T) :Array<any>...function createArray<T> (length: number, value: T) :Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3.'x'); // ['x', 'x', 'x']
Copy the code

– The union type and returns a value

function getLength(something: string | number) :number {
    return something.length;
}
Copy the code

We should strictly follow this syntax to write ✍️ without returning void

– the plugin

Use ESlite to standardize the code we write

  • AlloyTeam ESLint

  • reference

  • Ps TS Quick reference table for error messages

Company project Private inconvenient to post code and project address