preface

Vue and React are among the most popular and ecological front-end frameworks available. The framework itself is not superior or inferior, only applicable, and the most important goal is to choose the technology that fits our business scenario and team base.

The body of the

Design idea

vue

Vue’s website states that it is an incremental framework with a bottom-up incremental design. Here we need to clarify the concept of what an incremental framework is. Based on declarative rendering (view template engine), we can build a complete framework by adding component systems (Components), client-side routing (VUE-Router), and large-scale state management (VUEX). Vue covers all of these things from a design perspective, but you don’t have to start with everything, because you don’t have to. This is optional, both in terms of learning and in practical situations. Declarative rendering and component systems are part of Vue’s core library, while client-side routing, state management, and build tools all have specific solutions. These solutions are independent of each other, and you can build on top of the core any number of other components you want, not necessarily all of them. It can be seen that the “progressive” is actually the way Vue is used, and also reflects the design concept of Vue.

react

React advocates functional programming, so it advocates pure components, immutable data, and one-way data flow. Of course, bidirectional data flow can also be implemented manually, such as onChange and setState to achieve a bidirectional data flow. React’s three biggest features are declarative, componentized, and multiterminal (native, Node) rendering.

  1. React focuses on the View layer and works with other libraries (e.g., Redux, Mobx, etc.) along with the MV* architecture.
  2. React introduces the concept of virtual DOM, which greatly improves page rendering performance and can be rendered at Native or server.
  3. Unidirectional data flow. React data is transmitted through props from top to bottom. Users only care about data state updates.
  4. React uses declarative rendering to improve code readability and maintainability.
  5. Componentize. React components are first-class citizens.

Write the grammar

vue

Vue recommends the single file component format of Webpack + VUe-Loader. Vue retains the separate writing method of HTML, CSS and JS, so that the existing front-end developers can keep the original habit when developing, which is closer to the common Web development way. The template is ordinary HTML, and the style directly uses CSS.

react

React doesn’t have a template, it’s just a rendering function. React recommends using JSX + inline style, which translates HTML and CSS into JavaScript. JSX is really a set of syntactic sugar that uses XML syntax to make it easier to describe tree structures. In React, all components rely on JSX for rendering. You can write xmL-like syntax in Render (), which will eventually be compiled into native JavaScript.

component

vue

Vue component definitions are represented by xx.vue files. Vue components combine HTML, CSS, and JS together in the following form:

/ / template (HTML)
<template>
  <div>{{name}}</div>
</template>

// Data management (js)
<script>
export default {
  name: 'CompoenentName'.data() {
    return {
      name: 'xx'}}}</script>

/ / style sheet (CSS)
<style scoped>

</style>

Copy the code

react

React is recommended to use JSX or JS files to represent components. React supports both class components and functional components. React uses {} to wrap variables.

Note: Component names must begin with a capital letter. React will treat components that begin with a lowercase letter as native DOM tags. For example,

represents an HTML div tag, and
represents a component.

The following defines the react class and functional components

/ / class components
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: 'hello world'
    };
  }
  render() {
    rerurn(<div>{msg}</div>); }}export default App;
Copy the code
// Functional components
import React from 'react';

function App() {
  return (<div>hello world</div>);
}

export default App;
Copy the code

Component data interaction

Component data interaction refers to the transfer of data between parent, sibling, and cross-tier components. Sibling components can pass numbers between them through the event bus or through the parent component

vue

Parent-child component data interaction

In vUE, the parent component passes data to the child component via props. The child component fires a custom event using $emit. The parent component listens for the custom event of the child component to get data from the child component.

// Use $emit to pass custom event myEvent:
<template>
  <div @click="changeName">{{name}}</div>
</template>

<script>
export default {
  name: 'Child'.data() {
    return {
      name: 'xxx'}},methods: {
    changeName() {
      this.name = 'new Name';
      this.$emit('myEvent'.this.name); }}}</script>
Copy the code
// The parent component uses @myevent to listen for custom events. The callback function argument is the data returned by the child component:
<template>
  <div>
    <Child @myEvent="getName"></Child>
  </div>
</template>

<script>
import Child from './Child';

export default {
  components: {
    Child
  },
  methods: {
    getName(name) {
      console.log(name)
    }
  }
}
</script>
Copy the code

Cross-component data interaction

Inject a dependency into all descendants of an ancestor component via provide/inject, no matter how deep the component hierarchy is, and remains in effect as long as the upstream/downstream relationship is established.

// Upper component Settings provide
<script>
export default {
  provide: { // Define the provide option
    message: 'This is a big news'
  }
}
</script>
Copy the code
// The underlying component defines inject
<template>
  <div>{{message}}</div>
</template>

<script>
export default {
  name: 'Children'.inject: ['message']}</script>

Copy the code

react

Parent-child component data interaction

In React, the parent component uses the props to pass data and the callback function to its children. The children use the callback function to return data. The parent component uses the callback function to get data from the children.

/ / child component
import React, { useState } from 'react';

function Children(props) {
  const { myEvent } = props;

  const changeName = () = > {
    myEvent('new name');
  };
  return <div onClick={changeName}>Modify the name</div>;
}
Copy the code
/ / the parent component
function Parent() {
  const changeName = name= > {
    console.log(name);
  };
  return <Children myEvent={changeName}></Children>;
}
Copy the code

Cross-component data interaction

Context provides a way to pass data across the component tree without manually adding props for each layer of components.

// Context allows us to pass values deep into the component tree without explicitly traversing each component
import React from 'react'
const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>); }}function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />; }}Copy the code

State set management tool

vue

Vue uses VUEX for state management. Vuex introduces concepts of State and Getter to define State. Use Mutation and Action to change the state; Module is introduced for modularization segmentation of state; Introducing plug-ins to snapshot, record, and track state; MapState, mapGetters, mapActions, and mapMutations helper functions are provided to facilitate developers to deal with store in the VM. The specific relationship is as follows:

  1. Mount the state that needs to be shared to state: this.$store.state or mapState helper function to call.
  2. Create state via getters: call this.$store.getters. A state can be derived from a new state, and Vuex also provides mapGetters helper functions to help us use the states in Getters in our components.
  3. Use mutations to change state: passthis.$store.commitTo invoke. Mutations is also a pure object, which contains many methods to change state. The parameters of these methods receive state and change in the function body. In this case, the data used by the component will also be changed, realizing responsiveness. Vuex provides the mapMutations method to help us invoke the mutations method in a component.
  4. Use actions to handle asynchronous operations:this.$store.dispatchTo invoke. Actions is similar to mutations, except that mutations are submitted by Actions, rather than directly changing the status. Actions can contain any asynchronous action. That is, if there is a requirement to change the state after an asynchronous operation, we should call actions in the component first for the asynchronous action, and then call mutations from Actions to change the data. Call the Actions method in the component using the this.$store.dispatch method, or use mapMutations.

react

React uses Redux for state management. It was developed to solve communication problems between react components. It is recommended that data be managed in REDUx to facilitate data unification and management.

Redux’s process:

  1. CreateStore: remove the createStore from the redux tool to generate a store.
  2. Create a Reducer and pass it into createStore to aid in store creation. Reducer is a pure function that receives the current state and action and returns a state. Whatever state is returned, the store state is the same. It should be noted that reducer cannot directly operate the current state, but needs to return a new state. To create a default state for the store is to create a default value for a reducer parameter.
  3. The component uses the state in store by calling the store.getState method, which is mounted on its own state.
  4. The component generates user actions and calls the actionCreator method to create an action that is passed to the Reducer using the store.dispatch method.
  5. The reducer makes a judgment on the labeling information on the action and processes the new state, and then returns the new state. At this time, the store data will change. The state returned by reducer can be obtained by store.getState.
  6. We can use the store.subscribe method in a component to subscribe to data changes. That is, we can pass in a function that will execute when the data changes, in which the component will fetch the latest state.

React Hooks

Unique to React, vue does not have the concept of Hooks. React creates components in two ways: class components and functional components. Class components can define state, have life cycles, etc., but functional components do not, so react introduces hooks.

useState

UseState is the most basic API that passes in an initial value and gets a new value every time the function executes.

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={()= > setCount(count + 1)}>+</button>
      <h1>{count}</h1>
      <button onClick={()= > setCount(count - 1)}>-</button>
    </div>
  )
}

ReactDOM.render(<Counter />.document.getElementById('root'));
Copy the code

useEffect

A crucial Hooks API, useEffect, as the name implies, is used to handle side effects caused by various state changes, that is, logic that is executed only at certain moments, and can be used for the lifecycle: ComponentDidMount/componentDidUpdate/componentWillUnMount.

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';

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

  // => componentDidMount/componentDidUpdate
  useEffect(() = > {
    // update 
    document.title = `You clicked ${count} times`;
    // => componentWillUnMount
    return function cleanup() {
    	document.title = 'app';
    }
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

ReactDOM.render(<Example />.document.getElementById('root'));
Copy the code

useRef

CreateRef objects: class components, React elements use React. CreateRef, function components use useRef.

UseRef returns a mutable REF object whose current property is initialized as the passed parameter (initialValue).

const refContainer = useRef(initialValue);
Copy the code

ForwardRef: Function components cannot receive ref properties like class components because they have no instance. The parent can manipulate the parent’s ref object. The forwardRef forwards the REF object in the parent component to the DOM element in the child component. The child component accepts props and ref as parameters.

function Child(props,ref){
  return (
    <input type="text" ref={ref}/>
  )
}
Child = React.forwardRef(Child);
function Parent(){
  let [number,setNumber] = useState(0); 
  // When using the class component, creating a ref returns an object whose current property value is null
  // It has a value only if it is assigned to an element's ref attribute
  // So the parent component (class component) creates a ref object and passes it to the child component (class component), which has elements inside it
  // Then the parent can manipulate an element in the child
  // But the function component cannot receive the ref attribute 
  // the forwardRef is needed
  const inputRef = useRef();//{current:''}
  function getFocus(){
    inputRef.current.value = 'focus';
    inputRef.current.focus();
  }
  return (
      <>
        <Child ref={inputRef}/>
        <button onClick={()= >setNumber({number:number+1})}>+</button>
        <button onClick={getFocus}>Get focus</button>
      </>)}Copy the code

useContext

  • Receives a context object (the return value of React. CreateContext) and returns the current value of the context
  • The current context value is determined by the < MyContext.provider > value prop of the upper-layer component closest to the current component
  • When the most recent

    update is made to the component’s upper layer, the Hook triggers a rerender and uses the latest context value passed to MyContext Provider
  • UseContext (MyContext) is equivalent to static contextType = MyContext or < myContext.consumer > in the class component
import { useState, useContext, createContext } from 'react';
import ReactDOM from 'react-dom';

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

// 2. Create Provider
const UserProvider = props= > {
  let [username, handleChangeUsername] = useState(' ');
  return (
    <UserContext.Provider value={{ username.handleChangeUsername}} >
      {props.children}
    </UserContext.Provider>
  );
};

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

const App = () = > (
  <div>
    <UserProvider>
      <Pannel />
    </UserProvider>
  </div>
);

ReactDOM.render(<App />.document.getElementById('root'));
Copy the code

useCallback

Grammar:

const memoizedCallback = useCallback(() = > { doSomething(a, b); }, [a, b]);
Copy the code

Return value memoizedCallback is a Memoized callback. Pass inline callbacks and a series of dependencies. UseCallback will return a Memoized version of the memory that changes only if one of the dependencies changes.

Foo.js

import React from 'react';

const Foo = ({ onClick }) = > {

    console.log('Foo:'.'render');
    return <button onClick={onClick}>Foo component button</button>;

};

export default React.memo(Foo);
Copy the code

App.js

import React, { useCallback, useState } from 'react';
import Foo from './Foo';

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

    const fooClick = useCallback(() = > {
        console.log('Clicked the button on the Foo component'); } []);return (
        <div>
            <p>{count}</p>
            <Foo onClick={fooClick} />
            <br />
            <br />
            <button onClick={()= > setCount(count + 1)}>count increment</button>
        </div>
    );
}

export default App;
Copy the code

If you click the Count Increment button, the Foo component is not rerendered. If you use useCallback or React. Memo, Foo will still be rerendered as long as you change any variables of the parent component.

useMemo

Grammar:

const memoizedValue = useMemo(() = > computeExpensiveValue(a, b), [a, b]);
Copy the code

Returns an memoized value. Pass create function and dependency array. UseMemo recalculates memoized values only when one of the dependencies changes. This optimization helps avoid expensive calculations on each render.

  • Data can be cached, computed like Vue, and automatically recalculated based on dependency changes
  • For example, there are two child components Foo and Bar in the App component. When the props passed to Foo in the App component change, the state of the App component changes and the render is redone. Both the Foo and Bar components are also re-rendered. Now we can use useMemo to optimize it so that when Foo props changes, only Foo render and Bar does not re-render.

Foo.js

import React from 'react';

export default ({ text }) => {
    console.log('Foo:'.'render');
    return <div>Foo component: {text}</div>
}
Copy the code

Bar.js

import React from 'react';

export default ({ text }) => {
    console.log('the Bar:.'render');
    return <div>Bar component: {text}</div>
}
Copy the code

App.js

import React, { useState, useMemo } from 'react';
import Foo from './Foo';
import Bar from './Bar';

export default() = > {const [a, setA] = useState('foo');
    const [b, setB] = useState('bar');

    const foo = useMemo(() = > <Foo text={ a} / >, [a]);
    const bar = useMemo(() = > <Bar text={ b} / >, [b]);

    return (
        <div>
            { foo }
            { bar }
            <br />
            <button onClick={() = >SetA (' modified Foo')}> Modifies the attributes passed to Foo</button>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <button onClick={() = >SetB (' Modified Bar')}> Modifies the properties passed to Bar</button>
        </div>)}Copy the code

When we click on different buttons, the console will only print one output, change a or B, and only one of the A and B components will be re-rendered. UseCallback (fn, deps) equivalent to useMemo(() => fn, deps)

Customize the Hook

Custom hooks are more of a convention than a feature. If the function name starts with use and calls other hooks, it is called a custom Hook.

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

function useNumber(){
  let [number,setNumber] = useState(0);
  useEffect(() = >{
    setInterval(() = >{
        setNumber(number= >number+1);
    },1000);
  },[]);
  return [number,setNumber];
}
Copy the code

HOC

HOC(full name of higher-order Component) is an advanced use of React, mainly for the reuse of components. HOC is a way to take a component and return a higher-level component. During React development, there were a number of situations where components needed to be “enhanced”, such as adding or modifying certain props, managing permissions, and other optimizations. If the functionality is for multiple components, and each component has the same set of code, it’s obviously not wise to use HOC.

  • Code reuse, code modularization
  • Increases the censored props
  • Rendering hijacked

1. You can modify the props or add new props to add, delete, or modify the props. For example, if you wanted to add props to the wrappedComponent, you could do this:

function control(wrappedComponent) {
  return class Control extends React.Component {
    render(){
      letprops = { ... this.props,message: "You are under control"
      };
      return <wrappedComponent {. props} / >}}}Copy the code

This way, you can use the message props in your component

2. Rendering hijack here is not that you control the details of how it renders, but whether or not it renders. Because the details are controlled by the Render method inside the component, you have no control over the render details. For example, a component can load data without completing loading. , you can write:

function loading(wrappedComponent) {
  return class Loading extends React.Component {
    render(){
      if(!this.props.data) {
        return <div>loading...</div>
      }
      return <wrappedComponent {. props} / >}}}Copy the code

In this case, if the parent does not pass in data, only loading… Does not display the specific contents of the component