(1) a preliminary study

HMTL rendering process

This structured text is HTML text, and each element in HTML corresponds to a node in THE DOM. Thus, DOM nodes naturally form a tree structure called DOM tree because of the hierarchical inclusion of HTML elements. To render an HTML page, the browser first parses the HTML text to build a DOM tree, and then renders the interface that the user sees from the DOM tree. When the interface content needs to be changed, the nodes in the DOM tree are changed.

Pure functions

The React concept boils down to a formula like this: UI=render(data) the user should see the UI as the result of a function called render(in this case) that takes only data as arguments.

This function is a pure function. The so-called pure function refers to a function that has no side effects and its output is completely dependent on the input. If the input of two function calls is the same, the result will be absolutely the same. Thus, the final user interface, in the case of the render function, depends entirely on the input data.

The React ChuXie

React has a very simple function and is mainly responsible for rendering. Existing frameworks, such as Angular, are large and comprehensive. Angular almost doesn’t need other tools to support react.

PS: react feels like VScode or sublime requires a variety of plugins to write code, while angular has a lot of functionality like webstorm

What’s the React

DOM manipulation with scripts is expensive. Think of the DOM and JavaScript as islands, each connected by a toll bridge. Each time JS accesses the DOM, it has to cross the bridge and pay a “toll fee”. The more times you access the DOM, the higher the fee.

Therefore, the recommended course of action is to minimize the number of bridge crossings and try to stay on ECMAScript Island. React’s virtual DOM is valuable for this reason. It creates virtual DOM’s and stores them. Whenever the state changes, it creates new virtual nodes to compare with the previous ones and render the changed parts.

There’s no dom fetching or manipulation, just rendering, so React is a UI framework.

Component life cycle

When a component is initialized, it fires five hook functions:

1, getDefaultProps ()

Set the defaultProps. You can also set the default properties of the component using defaultProps.

This function is only used in component classes created by the React. CreateClass method.

2, getInitialState ()

This hook function is not available when using es6’s class syntax; you can define this.state directly from constructor. At this point, access this.props.

This function is only used in component classes created by the React. CreateClass method.

3, componentWillMount ()

It is called only when the component is initialized, not later when the component is updated, and only once throughout its life cycle, when state can be changed.

4, render ()

React creates the virtual DOM, performs the diff algorithm, and updates the DOM tree. You can’t change state at this point.

Usually for a component to function, it always renders something, the render function doesn’t do the actual rendering action, it just returns a structure described by JSX, and React handles the rendering process. The render function returns null or false, which tells React that the component doesn’t need to render any DOM elements this time. Note that the render function should be a pure function, depending entirely on this.state and this.props, without any side effects. Calling this.setState in the render function is definitely wrong, because a pure function should not cause state changes.

5, componentDidMount ()

The Render function returns something that has already been rendered, and the component has been “loaded” into the DOM tree. Called after the component has rendered, the dom node can be retrieved and manipulated by this.getDomNode () only once.


Five hook functions are also fired on update:

6, componentWillReceivePorps (nextProps)

Not called when the component is initialized, but when the component accepts new props.

7, shouldComponentUpdate (nextProps nextState)

React performance tuning is an important part of the process. If the props and state are the same, return false to block the update, because the same property state must generate the same DOM tree. In this way, there is no need to create a new DOM tree to compare the old DOM tree with the diff algorithm, which saves a lot of performance, especially when the DOM structure is complex. Calling this.forceUpdate skips this step, however.

8, componentWillUpdate (nextProps nextState)

It is not called when the component is initialized, but only when the component is about to be updated, at which point you can change state

9, render ()

The render function is re-executed when the component’s state or props changes

10, componentDidUpdate ()

It is not called when the component is initialized. It is called after the component is updated, at which point the DOM node can be obtained.

There is also an unload hook function

11, componentWillUnmount ()

Called when a component is about to unload, and some event listeners and timers need to be cleared.

React has a total of 10 function cycles (render repeats once). These 10 functions can meet all of our requirements for component operations and improve development efficiency and component performance.

Render and shouldComponentUpdate are also the only functions in the React lifecycle that require a return result. The return of the Render function will be used to construct the DOM object, while the shouldComponentUpdate function returns a Boolean that tells the React library whether the component should continue during the update.

V16 lifecycle function usage recommendations

class ExampleComponent extends React.Component {
  // Used to initialize state
  constructor() {}
  / / used to replace ` componentWillReceiveProps `, this function will be initialized and ` update ` is invoked
  // Because this function is static, we can't get 'this'
  // If the comparison 'prevProps' is needed, maintain it separately in' state '
  static getDerivedStateFromProps(nextProps, prevState) {}
  // Determine whether a component needs to be updated
  shouldComponentUpdate(nextProps, nextState) {}
  // called after the component is mounted
  // You can request or subscribe in this function
  componentDidMount() {}
  // To get the latest DOM data
  getSnapshotBeforeUpdate() {}
  // The component is about to be destroyed
  // You can remove subscriptions, timers, etc
  componentWillUnmount() {}
  // called after the component is destroyed
  componentDidUnMount() {}
  // called after component update
  componentDidUpdate() {}
  // Render component functions
  render() {}
  // The following functions are not recommended
  UNSAFE_componentWillMount() {}
  UNSAFE_componentWillUpdate(nextProps, nextState) {}
  UNSAFE_componentWillReceiveProps(nextProps) {}
}
Copy the code

The rendering process for parent and child components

Because the Render function itself does not render or load content into the DOM tree, it simply returns a JSX object, and the React library decides how to render it based on the returned object. The React library, on the other hand, must combine the results returned by all the components in order to know how to generate the corresponding DOM changes. Therefore, the React library only calls the Render function of the three Counter components to complete the loading process, and then calls the componentDidMount function of each component in turn to end the loading process.

React componentization

One component of React is clearly made up of dom views and state data. The two parts are distinct.

State is the data center whose state determines the state of the view. At this time, it seems to be a little different from the MVC development mode we have been advocating. Without Controller, how will user interaction be handled and who will manage data changes?

However, that’s not what React is concerned with, it’s just about rendering the UI. Unlike other frameworks that listen for data to dynamically change the DOM, React uses setState to control view updates.

SetState will automatically call the render function, triggering the view to be re-rendered, and will not trigger an update if only the state data changes without calling setState.

A component is a view module that has its own function. Many small components make up a large component, and the entire page is composed of components. The advantage is that it is easy to reuse and maintain.

UI = render(data)

The React component acts as the render function and should be a pure function with no side effects. Modifying the value of props is a side effect that components should avoid.

Component category

Concept: A component, simply put, is a separate, reusable piece of code that performs a specific function.

  • Container components only care about logic, not page rendering
  • UI components don’t care about logic, just page rendering
  • Stateless components do not have the render() function, just a function that does not declare periodic functions, which is more efficient

React Diff algorithm

When a component is updated, react creates a new virtual DOM tree and compares it to the previously stored DOM tree. This process uses the diff algorithm, so it is not used during component initialization.

React proposes an assumption that the same nodes have similar structures, while different nodes have different structures. Based on this assumption, layer by layer comparison, if the corresponding node is found to be different, the old node and all its children are deleted and replaced with the new node. If it is the same node, only property changes are made.

List for diff algorithm is slightly different, because the list is usually has the same structure, in the node list to delete, insert, sorting, the overall operation of a single node is much better than contrast one by one by one to replace, so in creating a list you need to set up the key value, so the react to distinguish who is who. Of course, we can do this without writing the key, but this usually generates a warning telling us to add the key to improve react performance.

JSX > createElement > Virtual DOM (JS object) > real DOM

Virtual Dom comparison algorithm

Different types of elements

Whenever the root element has a different type, React will unload the old tree and rebuild the new one. Any adjustment from to or from

to

, or from


When the tree is uninstalled, the old DOM node is destroyed. Component instances call componentWillUnmount(). When a new tree is built, new DOM nodes are inserted into the DOM. Component instances will call componentWillMount() and componentDidMount() in turn. Any state associated with the old tree is discarded.

All components under the root node will be uninstalled and their state destroyed.

DOM elements of the same type

When comparing two React DOM elements of the same type, React looks at their properties, keeps the same underlying DOM node, and updates only the changed properties.

Component elements of the same type

When components are updated, instances remain consistent so that state can be preserved between renders. The React by updating the underlying component instance props to create new elements, and, in turn, calls on the underlying instance componentWillReceiveProps () and componentWillUpdate () method.

Next, the render() method is called, and the comparison algorithm recursively processes the previous result with the new one.

React Diff algorithm flowchart

The key role

The React DOM first compares the sequence of elements and only updates the changed parts during rendering.

Key importance: Improve the efficiency of comparison

Keys help React identify elements that have changed when elements are added or removed from the DOM. So you should give each element in the array a definite identity.

Use the array subscript as the key. It looks like the key value is unique, but it is not stable. The same Todoltem instance may have different subscripts in the array during different update processes, so using the subscript as the key will completely mess up React. Note that although the key is a prop, the component receiving the key cannot read the value of the key because the key and ref are special prop reserved by React and are not expected to be accessed directly by the component.

Why use setState to modify data?

The value of this.state changes the internal state of the component, but it does not drive the component to re-render.

What this.setstate () does is first change the value of this.state, and then drive the component through the update process so that the new value of this.state appears in the interface.

SetState is an asynchronous function, right?

SetState () queues up to change the component’s state and tells React by updating the state that the component and its children need to be rerendered. This is the primary method used to respond to event handlers and server responses to update user interfaces.

Remember that setState() is a request, not an immediate command to update the component. React may delay it and then merge multiple setstates () to update multiple components for better perceived performance. React does not guarantee that state updates will be applied immediately (re-render).

React can combine multiple setState() calls into a single call to improve performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values to calculate the next state. SetState () does not always update components immediately. It may be batch or delayed until later updates. This makes reading this.state immediately after calling setState() a potential pitfall. With componentDidUpdate or setState callback (setState(updater, callback)), both are guaranteed to fire after an update is applied.

Here’s an example:

For example, this code might not update counters:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
Copy the code

To fix it, use the second form of setState() to accept a function instead of an object. This function takes the previous state as the first argument and the props at which the update was applied as the second argument:

// Correct
this.setState((prevState, props) = > ({
  counter: prevState.counter + props.increment
}));
Copy the code

SetState () always causes rerendering unless shouldComponentUpdate() returns false. If mutable objects are used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), only calling setState() when the new state is different from the previous state can avoid unnecessary re-rendering.

Not being able to write this.setstate () inside render() will result in loop modification

Write the React component

ES6’s class class can be thought of as a syntactically sugar of a constructor. Extends implements inheritance between classes — defining a class Main that inherits all properties and methods from React.component.component.component.component.component.component.component.component.component.component.component.component.component.component.component.component.class.

Constructor is called when the object is instantiated. Super calls the constructor of the superclass to create an instance object of the superclass, this, which is then modified with the constructor of the subclass.

super(props)

If super(props) is not called in the constructor, then after the component instance is constructed, any member functions of the class instance cannot access the props passed by the parent component through this.props. Obviously, assigning this. Props is one of the jobs of the react.componentconstructor.

ShouldCompnentUpdate life cycle

It is generally accepted practice to do “shallow comparisons” in the generic shouldCompnentUpdate function; If a “deep comparison” is needed, it is the behavior of a particular component and needs to be written by the developer for that component.

PureComponent

React15.3 adds a new class called PureComponent, formerly PureRenderMixin, which is basically the same as Component, except that it automatically performs a shallowEqual (shallow comparison) before render to decide whether to update the Component. Shallow comparison is similar to shallow replication in that only the first layer is compared. Using PureComponent eliminates the need to write shouldComponentUpdate if the props and state of the component are:

  1. The references and the first layer data are unchanged,renderMethod doesn’t fire, that’s what we need to achieve.
  2. Although the first layer of data does not change, the reference changes, resulting in virtualDOMThe waste of calculation.
  3. The first layer data changes, but the reference does not change, will not render, so need to be very careful to manipulate the data.

React makes only shallow comparisons for performance, hence immutable.js

immutable.js

High order component

A higher-order component is a function that takes a component as an argument and returns a new component

const EnhancedComponent = higherOrderComponent(WrappedComponent);
Copy the code

A component converts the props property to UI, and a higher-order component converts a component to another new component.

Higher-order components are common in React third-party libraries, such as Redux’s Connect method and Relay’s createContainer.

Refs properties

Create the Refs

Create refs with react.createref () and get the React element from the ref attribute. When constructing components, refs are usually assigned to a property of the instance so that you can use them anywhere in the component.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />; }}Copy the code

The value of ref depends on the type of node:

  • whenrefWhen the attribute is applied to a normal HTML element,React.createRef()Will receive the underlying DOM element as itscurrentProperty to createref
  • whenrefProperty is used for a custom class component,refObject will receive the mounted instance of the component as itscurrent
  • You cannot use the ref attribute on functional components because they have no instances.

The React – the Router routing

The Router is a component of React. It is not rendered. It is a configuration object that creates internal routing rules and displays components based on matched routing addresses.

Route binds routing addresses to components. Route has the nesting function and represents the inclusion relationship of routing addresses, which is not directly related to the nesting between components. Route can pass seven attributes to the bound component: children, history, location, params, Route, routeParams, routes. Each attribute contains information about the Route.

Commonly used components include children (components distinguished by routing inclusion relation) and Location (including address, parameter, address switching mode, key value and hash value).

The React-router provides a Link tag, which encapsulates the A tag. It is important to note that clicking a Link is not the default way to jump. The React-router disables the default behavior of the A tag and uses pushState to convert the hash value.

The process of switching pages is that when the Link label or backward forward button is clicked, the URL address will be changed first. The Router listens to the change of address and matches the corresponding component according to the path attribute of Route, changes the state value to the corresponding component, and calls setState to trigger the render function to re-render dom.

Routing (load on demand)

When there are too many pages, the project will become bigger and bigger, especially for single-page applications, the first rendering speed will be slow, at this time, you need to load on demand, only when switching to the page to load the corresponding JS file. React with Webpack to load on demand is easy. Change the component of Route to getComponent, use require.ensure to get components, and configure chunkFilename in webpack.

const chooseProducts = (location, cb) = > {
    require.ensure([], require => {
        cb(null.require('.. /Component/chooseProducts').default)
    },'chooseProducts')}const helpCenter = (location, cb) = > {
    require.ensure([], require => {
        cb(null.require('.. /Component/helpCenter').default)
    },'helpCenter')}const saleRecord = (location, cb) = > {
    require.ensure([], require => {
        cb(null.require('.. /Component/saleRecord').default)
    },'saleRecord')}constRouteConfig = (<Router history={history}> <Route path="/" Component ={Roots}> <IndexRoute Component ={index} />// home <Route path="index" component={index} /> <Route path="helpCenter" getComponent={helpCenter} />// helpCenter <Route Path ="saleRecord" getComponent={saleRecord} />// Sales record <Redirect from='*' to='/' /> </Route> </Router>);Copy the code

Communication between components

React advocates one-way data flow, often referred to as top-down or one-way data flow. Any state is always owned by some particular component, and any data or UI exported from that state can only affect components down the tree.

There are many ways to solve communication problems:

  1. If it is a parent-child relationship, the parent can pass a callback function to the child as an attribute, and the child can call the function directly to communicate with the parent.
  2. The component hierarchy is deeply nested, and you can use the context getChildContext to pass information, so that instead of passing functions down the hierarchy, any child of the hierarchy can be accessed directly through this.context.
  3. Fraternal components cannot communicate directly with each other; they can only use their superiors at the same level as staging stations. If the sibling components are at the highest level, in order for them to communicate, they must have another layer of components on top of them, and this layer of components holds the data and transmits the information, which is essentially what Redux does.
  4. Information between components can also be passed through global events. Different pages can pass data as arguments, and the next page can be retrieved using location.param.

React event delegate

In JSX, we see a component that uses onClick, but instead of producing HTML that uses onClick directly, it uses Event Delegation to handle click events. No matter how many onclicks occur, all you end up doing is adding an event handler to the DOM tree, hanging from the topmost DOM node.

All click events are captured by this event handler and then assigned to specific functions depending on the component, so using event delegates is of course better than mounting an event handler for each onClick. Because React controls the life cycle of components, all event handlers are automatically cleared when unmounted, and memory leaks are no longer an issue.

(2) the advanced

Redux

The basic principle of

The basic principle of Flux is “one-way data flow”, on which Redux emphasizes three basic principles:

  • Single Source of Truth;

    In Flux, an application can have multiple stores, and the status data of the application is often divided into several stores for storage and management according to their functions.

    Redux’s solution to this problem is to maintain a single Store for the entire application, and the data source for all components is the state on that Store.

  • Keep the State read-only.

    Keep the state read-only, that is, you cannot change the state directly. To change the state of the Store, you must distribute an action object. This is no different from Flux’s requirement.

    Of course, to drive UI rendering, you need to change the state of the application, but the way to change the state is not to modify the value of the state, but to create a new state object that is returned to Redux, and Redux does the new state assembly.

  • Changes are made with pure functions only.

    In Redux, the function signature of each reducer is as follows: Reducer (state, action) The first parameter state is the current state, the second parameter action is the received action object, and the reducer function needs to do Reducer must be a pure function, that is, the return result of the reducer must be completely determined by the state and action parameters without any side effects. The parameter state and action objects cannot also be modified.

Redux core API

Redux consists of three parts: Store, Reducer, and Action.

store

The core of Redux is store, which is generated by createStore(Reducer, defaultState) provided by Redux. Three methods are generated, getState(), Dispatch () and subscrible().

  • GetState () : stored data, state tree;
  • Dispatch (Action) : Dispatches an action and returns an action, which is the only way to change the data in the store;
  • Subscrible (Listener) : Registers a listener that is called when the store changes.

reducer

Reducer is a pure function that calculates the new state based on previousState and action. reducer(previousState,action)

action

An action is essentially a JavaScript object that must contain a Type field to indicate the action to be performed, and other fields can be customized as required.

const ADD_TODO = 'ADD_TODO'
Copy the code
{
  type: ADD_TODO,
  text: 'Build my first Redux app'
}
Copy the code

integration

The interaction between them can be summarized in the following figure:

Conceptual analysis:

Redux consists of three parts: Store, Reducer, and Action.

A store is an object that has four main methods:

1, the dispatch:

Action distribution — In createStore, we can modify dispatches with middleware. For example, when an action is sent to a dispatch, the reducer is triggered immediately. Sometimes we don’t want it to be triggered immediately, but wait until the asynchronous operation is complete. When redux-thunk is used to modify the dispatch object, it can pass in a function. In this function, we can manually dispatch an action object. The process is controllable and asynchronous.

2, the subscribe:

Listen for changes in state – This function registers a listener to listen for changes in state when the Store calls The Dispatch. This function can be called when we need to know if the state has changed. It returns a function that can be called to cancel the listener.

Let unsubscribe = store.subscribe(() => {console.log('state changed ')})

3, getState:

Obtain the state in the store — When we changed the reducer state with action trigger, we need to get the data in the new state, after all, the data is what we want.

GetState is mainly needed in two places. First, after Dispatch gets the action, the Store needs to use it to obtain the data in the state and send this data to reducer. This process is automatically executed. Second, we use subscribe to listen to the change of state and call it to get new state data. If we do this step, it means we have succeeded.

4, replaceReducer:

Replace reducer and change the logic of state modification.

A store can be created using the createStore() method and accepts three parameters, the initial state of reducer and state merged by combineReducers and middleware changes to dispatch, the latter two parameters are not required. The main role of the Store is to link the actions to the Reducer and change the state.

action:

An action is an object where the type attribute is required and some data can be passed in. Actions can be created using actionCreactor. Dispatch means to send an action object.

reducer:

Reducer is a function that accepts a state and an action and returns a new state based on the action type. According to the business logic, it can be divided into many reducer, and then merge them through combineReducers. There are many objects in the state tree, and each state object corresponds to a Reducer.

const reducer = combineReducers({
     a: doSomethingWithA,
     b: processB,
     c: c
})
Copy the code

combineReducers:

In fact, it is also a reducer. It accepts the whole state and one action, and then disassemves the whole state and sends it to the corresponding Reducer for processing. All reducer will receive the same actions, but they will judge according to the action type. If there is a type, it will process it and return the new state, if there is no type, it will return the default, and then the scattered states will be combined to return a new state tree.

Process analysis:

  1. First callstore.dispatchwillactionPassed in as a parameter and used at the same timegetStateGets the current state treestateAnd registersubscribethelistenerListening to thestateChange, call againcombineReducersAnd will getstateandactionThe incoming.
  2. CombineReducers will pass the incoming state and action to all reducer, and return a new state according to the action type, triggering the update of the state tree. We call SUBSCRIBE to listen for state changes and use getState to get new state data.

The redux state and react state are completely unrelated, except for the name.


React-Redux

How does react-Redux work together

React-redux has two main features:

  • Connect: Connect container components to view components;
  • Provider: provides the context containing the store.
  1. React-redux provides its gay friends connect and Provider, one that associates components with Redux and the other that passes stores to components.
  2. The component sends actions through Dispatch. The Store calls the corresponding Reducer according to the type attribute of the action and passes in state and this action. The Reducer processes the state and returns a new state and puts it into the store. Connect listens for changes in the Store, calls setState to update the component, and the component’s props change as well.
  3. It is worth noting that connect, the Provider, mapStateToProps mapDispatchToProps is the react – story, the story itself and the react didn’t have anything to do, it’s just a data processing center, and react to produce no coupling, It’s react-Redux that binds them together.

Redux itself has nothing to do with React, it’s just a data processing center, and it’s react-Redux that binds them together.

Two methods of react-redux

connect

The nuggets data

Connect Connects the React component to the Redux Store. Connect is actually a higher-order function that returns a new component class connected to the Redux Store.

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
Copy the code

TodoList is a UI component, and VisibleTodoList is a container component automatically generated by React-Redux through the connect method.

  1. mapStateToProps: Extracts the required parts from the Redux state tree as props to the current component.
  2. mapDispatchToProps: Passes the response events (actions) that need to be bound to the component as props.

** Book materials **

export default connect(mapStateToProps, mapDispatchToProps) ( Counter);
Copy the code

What exactly does this connect function do? As a container component, you do two things:

  • A prop that converts state on the Store to an inner dumb component
  • Converts user actions in the inner fool component to actions sent to the Store.

Provider

The Provider implements global access to stores, passing stores to each component.

React context works by using the React context. Context can be passed between components.

If only redux is used, the flow looks like this:

component –> dispatch(action) –> reducer –> subscribe –> getState –> component

The react-redux process looks like this:

component –> actionCreator(data) –> reducer –> component

The three major functions of store: Dispatch, Subscribe and getState do not need to be written manually.

React-redux does this for us, and it provides two great gay friends, Provider and Connect.

A Provider is a component that accepts the Store as props and passes it down through the context so that any component in React can use the context to get the store.

This means that we can use Dispatch (action) in any component to trigger reducer to change state, listen to state changes with SUBSCRIBE, and then use getState to obtain the changed value. However, it is not recommended to do this, because it will make the data flow chaos, excessive coupling will also affect the reuse of components, and more trouble to maintain.

Connect –connect(mapStateToProps, mapDispatchToProps, mergeProps, options) is a function that takes four arguments and returns a function, wrapWithConnect, WrapWithConnect takes a component as an argument, wrapWithConnect(Component) internally defines a new component Connect(container component) and returns the component passed in (UI component) as a child of Connect.

So the full way to write it is: ‘connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)

MapStateToProps (state, [ownProps]) :

The mapStateToProps takes two parameters, the store state and the custom props, and returns a new object that is passed to the UI component as part of the props. We can return a custom object based on the data required by the component. Changes to ownProps also trigger mapStateToProps

function mapStateToProps(state) {
   return { todos: state.todos };
}
Copy the code

MapDispatchToProps (dispatch, [ownProps]) :

MapDispatchToProps, if it is an object, is bound to store as part of the UI component as props.

If it is a function that takes two parameters, bindActionCreators will bind the Action to dispatch and return an object that will be passed into the UI component as part of the props along with ownProps.

So whether the mapDispatchToProps is an object or a function, it will eventually return an object, and if it is a function, the key of that object is customizable

function mapDispatchToProps(dispatch) {
   return {
      todoActions: bindActionCreators(todoActionCreators, dispatch),
      counterActions: bindActionCreators(counterActionCreators, dispatch)
   };
}
Copy the code

The properties of the object returned by mapDispatchToProps are actionCreator. Since actionCreator is bound to Dispatch, action will be sent immediately when actionCreator is invoked instead of manual dispatch. Changes to ownProps also trigger mapDispatchToProps.

MergeProps (stateProps, dispatchProps ownProps) :

Merge the object returned by mapStateToProps() with mapDispatchToProps() and the props of the component itself into new props and pass it in to the component. By default, object. assign({}, ownProps, stateProps, dispatchProps) is returned.

The options:

In shouldComponentUpdate, the Connect container component should shallow compare store state and ownProps to determine if any changes are made to optimize performance. If it is false, no comparison is performed.

The connect function doesn’t really do much. Most of the logic is implemented in the wrapWithConnect function it returns, or rather in the Connect component defined within wrapWithConnect.


The big Store directory structure I used in the project is:

// index.js
import {createStore, compose, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import reducers from './reducers';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers, composeEnhancers(
  applyMiddleware(thunk)
));

export default store;
Copy the code
// reducers.js
Merge the small reducer
import {combineReducers} from 'redux-immutable'; // Provide immutable data
import {reducer as userReducer} from './user'
import {reducer as chatUserReducer} from './chat_user'
import {reducer as chatReducer} from './chat'

const reducer = combineReducers({
  user: userReducer,
  chatUser: chatUserReducer,
  chat: chatReducer
});

export default reducer;
Copy the code

The small store(for example) directory structure I used in the project is:

Core code:

// _reducer.js
import * as constants from './constants'
import {getRedirectPath} from '.. /.. /common/js/util'

const initState = {
  isAuth: false.msg: ' '.user: ' '.pwd: ' '.type: ' '
}

const defaultState = (localStorage.getItem('jobUser') && JSON.parse(localStorage.getItem('jobUser'))) || initState


export default (state = defaultState, action) => {
  switch (action.type) {
    case constants.AUTH_SUCCESS:
      localStorage.setItem('jobUser'.JSON.stringify({ ... state,msg: ' '.redirectTo: getRedirectPath(action.payload), ... action.payload }))return{... state,msg: ' '.redirectTo: getRedirectPath(action.payload), ... action.payload}case constants.LOAD_DATA:
      return{... state, ... action.payload}case constants.ERROR_MSG:
      return{... state,isAuth: false.msg: action.msg}
    case constants.LOGIN_OUT:
      return {redirectTo: '/login'. initState}default:
      return state
  }
}
Copy the code
// actionCreators.js
import * as constants from './constants'
import axios from 'axios'
const authSuccess = (obj) = > {
  const{pwd, ... data} = objreturn {type: constants.AUTH_SUCCESS, payload: data}
}
const errorMsg = (msg) = > {
  return {msg, type: constants.ERROR_MSG}
}

/ / register
export function register({user, pwd, repeatpwd, type}) {
  if(! user || ! pwd || ! type) {return errorMsg('Username and password must be entered')}if(pwd ! == repeatpwd) {return errorMsg('Password and confirmation password are different')}return dispatch= > {
    axios.post('/user/register', {user, pwd, type})
      .then(res= > {
        if (res.status === 200 && res.data.code === 0) {
          dispatch(authSuccess(res.data.data))
        } else {
          dispatch(errorMsg(res.data.msg))
        }
      })
  }
}

/ / login
export function login({user, pwd}) {
  if(! user || ! pwd) {return errorMsg('Username and password must be entered')}return dispatch= > {
    axios.post('/user/login', {user, pwd})
      .then(res= > {
        if (res.status === 200 && res.data.code === 0) {
          dispatch(authSuccess(res.data.data))
        } else {
          dispatch(errorMsg(res.data.msg))
        }
      })
  }
}

/ / logout
export function logoutSubmit() {
  return {type: constants.LOGIN_OUT}
}

/ / modify
export function update(data) {
  return dispatch= > {
    axios.post('/user/update', data)
      .then(res= > {
        if (res.status === 200 && res.data.code === 0) {
          dispatch(authSuccess(res.data.data[0))}else {
          dispatch(errorMsg(res.data.msg))
        }
      })
  }
}
Copy the code
// constants.js
export  const AUTH_SUCCESS = 'AUTH_SUCCESS'
export const LOGIN_OUT = 'LOGIN_OUT'
export const ERROR_MSG = 'ERROR_MSG'
export const LOAD_DATA = 'LOAD_DATA'
Copy the code
// index.js
import reducer from './_reducer'
import * as actionCreators from './actionCreators'
import * as constants from './constants'

export {reducer, actionCreators, constants}
Copy the code

React –> redux –> react

The Provider component accepts the Store of Redux as props and passes it down through the context.

Second,

  1. The connect function, when initialized, binds the mapDispatchToProps object to the Store,

  2. If the mapDispatchToProps is a function, after the Connect component gets the Store, bind the returned object to the Store based on the incoming Store. dispatch and action through bindActionCreators. The connect function returns a wrapWithConnect function, and wrapWithConnect is called and passed in a UI component, WrapWithConnect internally defines a Connect Component using class Connect extends Component. The UI Component passed in is a child of Connect.

  3. The Connect component then gets the store via context and the complete state object via store.getState, Passing state to mapStateToProps returns the stateProps object, the mapDispatchToProps object, or the mapDispatchToProps function returns a dispatchProps object, The props of the stateProps, dispatchProps, and Connect components are passed to the UI component via object.assign (), or mergeProps merged into props. We then call Store. Subscribe in ComponentDidMount, registering a callback function called handleChange to listen for state changes.

Three,

  1. In this case, the UI component can find actionCreator in props. When actionCreator is called, dispatch will be automatically called and getState will be called to get the entire state. At the same time register a listener to listen for state changes, store will get the state and action to the combineReducers,
  2. CombineReducers will pass state to reducer according to state key values, and actions to all reducer, reducer will be executed in turn to judge action. Type, if there is, a new state will be returned. If not, the default is returned.
  3. CombineReducers again merges the single state returned by the Reducer into a new complete state. Now the state has changed.
  4. After state returns a new value, Dispatch will call all the registered listener functions, including handleChange. Inside handleChange, getState will be called to get the new state value and a shallow comparison will be made between the old and new states. If they are the same, return. If they are different, call mapStateToProps to obtain the stateProps and compare the old and new stateProps. If they are the same, return and do not perform subsequent operations.
  5. If not, call this.setState() to trigger the update of the Connect component, pass in the UI component, trigger the update of the UI component, and then the UI component gets the new props and react –> redux –> react.

The above is a bit complicated, but the simplified version of the process is:

The Provider component accepts the Store of Redux as props and passes it down through the context.

The connect function receives the store from the Provider, then takes three parameters mapStateToProps, mapDispatchToProps, and the component, and passes state and actionCreator as props to the component. The component can then call actionCreator to trigger the Reducer function to return the new state. Connect listens for the state change and calls setState to update the component and pass the new state into the component.

Connect can be written very cleanly, mapStateToProps, mapDispatchToProps are just callbacks that are passed in, and connect will call them if necessary. The names are not fixed, or they can even be written without names.

Simplified version:

connect(state= > state, action)(Component);
Copy the code

How redux and React-Redux are implemented?

conclusion

The following diagram illustrates the workflow between them:


Story – thunk middleware

Code examples:

function createThunkMiddleware(extraArgument) {
	return ({ dispatch , getState }) = > next => action= > {
	if (typeofAction = = ="function'){
		return action(dispatch , getState , extraArgument);
	}
		returnnext(action); }}const thunk= createThunkMiddleware();
export default thunk;
Copy the code

Let’s look at the innermost function in the redux-thunk sequence, which is the function that actually handles each action object. First check the action type. If it is a function type, execute the action function and pass in dispatch and getState as arguments. Otherwise, next is called to let the next middleware continue processing the action, as described in the Redux-Thunk documentation.

The unidirectional data flow of Redux is a synchronous operation. Action objects drive the Redux process. After each action object is distributed to the Store, it is synchronously allocated to all reducer functions, each reducer is a pure function. The pure function does not produce any side effects. Naturally, it should be synchronized immediately after the data operation is completed. The results returned by reducer are synchronized to update the state data on the Store. This triggers the React component update process as a view.

When we want Redux to help with an asynchronous operation, our code also needs to distribute an Action object, because that’s what drives the Redux one-way data flow. But the action objects that trigger asynchronous operations are special, and we call them “asynchronous Action objects.” The action constructors in the previous examples all return a plain object containing several fields, the essential of which is Type, but the “asynchronous Action object” is not a plain JavaScript object, but a function. If there is no redux-Thunk middleware, the action object of such a function type will be sent all the way to the reducer function. The Reducer function cannot obtain the Type field from these action objects which are actually functions. So you can’t really do anything about it.

However, with the Redux-Thunk middleware, these action objects have no chance to touch the Reducer function and are intercepted at the middleware level by Redux-Thunk.

The job of redux-thunk is to check if an action object is a function, pass it through if it is not, and execute the function if it is a function. The Store dispatch function and the getState function are passed into the function as parameters. The process ends here and the asynchronous action object is not sent forward to the Reducer function.

React Middleware mechanism

In the Redux framework, the middleware processes action objects, and the dispatch function on Store is the action objects distributed. As described before, the action objects distributed through Dispatch will be sent to reducer. Before the action object enters the Reducer, it goes through the middleware pipeline.

In this middleware pipeline, each middleware receives the action object, and when it is processed, it passes the action object to the next middleware. Only after all the middleware has processed the action object, each middleware in this middleware pipeline receives the action object. After the action object is processed, it is the turn of the Reducer to deal with the action object only after all the middleware has processed the action object. However, if one of the middleware feels that it is no longer necessary to deal with this action object, The action object will not be handed over to the next middleware, so the processing of this action object is stopped and the reducer is no longer available.

Each middleware must define a function that returns a function that takes a next parameter, which in turn returns a function that takes an action parameter. The next parameter is itself a function that the middleware calls to notify Redux that its processing has finished.

Code examples:

// A middleware code that actually does nothing looks like this:
function doNothingMiddleware{{dispatch, getState)) {
	return function {next) {
		return function {action) {
			return next{action)
     }
	}
}
Copy the code

Functions that take action as arguments process the passed action object. Because JavaScript supports closure (Clousure), you can access the arguments of the above two functions in this function, so you can do a lot of things as needed, including the following functions:

  • Call the Dispatch dispatch to issue a new Action object;
  • Call getState to get the current state on the Redux Store;
  • Calling next tells Redux that the current middleware is done and Redux calls the next middleware;
  • Access all data on the Action object action. With these capabilities, a single middleware is sufficient to capture all the information on the Store and to control the flow of data.

Middleware is used to expand the function of dispatch function. Multiple middleware actually constitute a pipeline for dealing with action objects. Action objects can only be processed by Reducer after being successively processed by all middleware in this pipeline.

(3) start

React, react-router, and redux But how do you put them together and build a complete project?

Redux, react-router, react.js, redux, react-router, etc.

Import objects and methods from react.js, redux, and react-router.

import React, {Component, PropTypes} from 'react';
import ReactDOM, {render} from 'react-dom';
import {Provider, connect} from 'react-redux';
import {createStore, combineReducers, applyMiddleware} from 'redux';
import { Router, Route, Redirect, IndexRoute, browserHistory, hashHistory } from 'react-router';
Copy the code

3. Create top-level UI components according to requirements, and each top-level UI component corresponds to a page.

4. Create actionCreators and reducers, and combine all reducers into a large Reduer with combiner Creators. Create a store using createStore and introduce combineReducers and applyMiddleware.

Use connect to associate actionCreator, Reuder with the top UI component and return a new component.

6. Use the new component returned by Connect to deploy routes with the React-Router, and return a router.

7. Add the Router to the top-level component Provider and add store as the Provider property.

Call the Render Provider component and place it in the TAB of the page.

You can see that the top UI component is actually covered by four layers of components: Provider, Router, Route, and Connect. These four components do not change react in the view, they are only functional.


Making address:wq93