Reprint is prohibited by imweb community without permission

Before introducing componentization schemes, let’s take a quick look at React and Redux.

Why React

Ideally, the first step in componentization would be tagging a component, such as having a Header component, as shown in the figure below

Instead of focusing on the implementation inside the component, we only need to use one

The tag can call it and control what it displays and events by setting its properties.

class Page extends Component {
    render () {
        
       
}}Copy the code

OnAttend determines the event triggered when clicked anchorInfo determines the anchorInfo shown on the left and the members shown on the right

React already does this with the help of the JSX syntax.

Why Redux

In simple applications, the above componentization scheme is very clear because

Component is used by any other component without any side effects.

However, the data flow of React is one-way, and the data and methods of the child components can only be assigned by the parent component. Once the nesting level of components becomes deeper, data transmission becomes very complicated.

Take the Header component, which uses Avatar and Members internally. The Header sends the data and methods it receives to Avatar and Members.


//Header.js
class Header extends Component {
    render () {
        
        
    }
}
Copy the code

Of course, one might think that declaring the required data and methods directly in the Header, instead of getting them from the parent, would solve the problem of deep nesting, but then the data would be coupled to the component, and different projects would use different data sources for the headers. This means that you need to write a Header for each project, providing a different way to get the data.

On the other hand, assuming anchorInfo is also used in the DownloadBar of another component, the DownloadBar also needs to maintain this data.

If anchorInfo changes within both components, both need to notify the other component of the change as well, because anchorInfo should be unique. It is common for different components in a large application to share the same data source. If the components themselves maintain a copy of data, it is easy to cause data chaos.

The Redux framework solves this problem by changing React from a parent to a unified data store that delivers data to components in one direction.

  • The original React architecture
  • After adding Redux’s architecture

All data is stored in the Store, and no data is maintained internally.

The Store provides a dispatch method to trigger changes to data in the store. The value passed by Dispatch is called an action. After dispatch(actions), it will enter the reducer processing functions in the store. These reducer processing functions will be different according to different types of actions. The value returned by the Reducer will be the new data in the store. A Reducer corresponds to one data field in the store. Each reducer corresponds to one more data field in the store. When the data changes, the Store notifies the corresponding component to re-render.

Through the connect high-order function provided by the Redux framework, directly select the required data from store and declare the required methods into the component. These declare methods are the implementation of the specific logic of the component event, such as sending requests, reporting logic, etc. So the logic to call the dispatch(action) is usually included.

Based on React as a UI component library and Redux as a state management framework, we define four types of components.

Display components

The React component is our presentation component. It does not maintain any dynamic data internally, except for some data that is only relevant to the component itself. For example, in the Video component, playState is its internal state, and SRC must be passed in externally. It does not contain specific implementations of events, but only interfaces (such as onClick), which are left up to external callers.

Storage center Components

The storage center component is the Store in the Redux architecture mentioned above. The storage center component defines some Reducer handler functions and some middleware by default, as well as higher-order functions to connect Redux and React and methods to inject new Reducer into the store.

Data component

The data component is a collection of an action and the corresponding Reducer in the REDUx architecture. The data component provides various actions to call and defines corresponding actions to handle. The data component must reference the storage center component, because the data component must inject corresponding reducer processing functions into the store. For example, in the roomInfo data component, enterRoom, loadRoomInfo, leaveRoom actions are provided for the caller to use, and roomInfo data is automatically added to the store.

There are also dependencies among data components. For example, ChatMessage takes longpoll as the data component, because the Actions of Longpoll need to be processed in the Reducer of ChatMessage.

High order component

Higher-order components are the presentation and data components that are declared in connect higher-order components. Function to display the component after processing. In general, the components used are generally higher-order components. The higher-order component determines the properties and methods passed to the presentation component. Higher-order components are coupled to the business and are not reusable. The higher-order components are highly converged, while the presentation and data components are fully decoupled.

A higher-order component may contain multiple data components, such as the Ranklist presentation component, which needs to be provided by the roomInfo and Ranklist data components.

Higher-order components may not introduce any methods of data components, but simply import the corresponding data components and inject the Reducer into the store

import '@tencent/now-data-roomInfo'
Copy the code

Access the component

  1. Declare the storage center component.
  2. Declare appropriate higher-order components.
  3. If no corresponding higher-order component exists, the presentation component and data component are declared and created as new higher-order components.
  4. If there is no corresponding presentation component, create a required presentation component. Back to step2
  5. If there is no corresponding data component, create a required data component. Return to step 3
  6. Write entry files to introduce various high-level components.

We might look like this in real development

  1. We received a new requirement that the general layout was exactly the same as the previous project, except that the business was only performed in hand Q, and the video data source was provided by a new CGI.
  2. Identify the components we need In this example, the components we need are:
  3. The Header in the head
  4. Video Video
  5. The Message the Message
  6. Mercifully thumb up
  7. ToolPanel ToolPanel

  8. Look for higher-order components on TNPM and find the following higher-order components

  9. now-highorder-bubble
  10. now-highorder-message
  11. now-highorder-toolpanel
  12. now-highorder-header
  13. now-highorder-video

The components that can be used directly are

  • now-highorder-bubble
  • now-highorder-message
  • Now – Highorder – ToolPanel installs the corresponding component via TNPM
tnpm install @tencent/now-highorder-message @tencent/now-highorder-toolpanel 
@tencent/now-highorder-bubble
Copy the code

The onClose event defined by now-highorder-header can only be executed in the NOW APP, so it cannot be used.

The CGI data used by the data component referenced in now-highorder-video is an older version of CGI data and cannot be used.

  1. Customize a new header high-level component in your project. Use the same display and data components as in the now-highorder-header, still the now-display-header and now-data-header components. The method passed in by onClose is the new method only when connected through Connect. The corresponding display and data components are installed through TNPM
    tnpm install @tencent/now-data-roomInfo @tencent/now-display-header
    

    Create a new Header higher-order component, now-highorder-header2

    Import Header from '@tencent/now-display-header' import roomInfo from '@tencent/ now-data-roominfo '// Import data components import connect from 'react-redux' export default connect((state) => { const { roomInfo } = state return { roomInfo } }, (dispatch) => {return {onClose: () => {_. MQQ ('close') // hand q to call MQQ close interface}}})(Header)Copy the code

    4. Customize a new higher-order component of videoin the project, using the existing now-display-header as the display component. Since a new CGI is used, first create a new data component, now-data-videoInfo_v2. The data component must reference the addReducer method in the now-Store to inject new fields into the store.

    Import Video from '@tencent/now-display-video' import {loadVideo} from 'now-data-videoinfo_v2' // Import declared data components

    export default connect((state) => {
    const {
    url,
    } = state.videoInfo

    now-data-videoinfo_v2 import { addReducer } from '@tencent/now-store'; Export function loadVideo(roomId) {// Define action function... } function videoInfo (state = {// define reducer handler url: ",}, action) {... } addReducer({// inject new data into store videoInfo}) is introduced in the new video advanced component, TNPM install @tencent/now-display-video creates a new higher-order component now-highorder-video2 import Import {loadVideo} from 'now-data-videoinfo_v2' import {loadVideo} from 'now-data-videoinfo_v2' import {loadVideo} from 'now-data-videoinfo_v2' import {loadVideo} from 'now-data-videoinfo_v2 default connect((state) => { const { url, } = state.videoInfo return { src: url } }, (dispatch) => { return { onLoad: () => { return dispatch(loadVideo()) } } })(Video)Copy the code

    5. Compile the entry file index.js to introduce existing and newly created components and assemble the page.

    Import React, {Component} from 'React' connect } from 'react-redux' import Store from '@tencent/now-store'; // Import Header from './now-highorder-header2' // Import Video from './now-highorder-video2' import Message  from '@tencent/now-highorder-message' import Bubble from '@tencent/now-highorder-bubble' import ToolPanel from '@tencent/now-highorder- toolPanel 'class PageContainer extends Component {// Create react root render () {return (// reference each Component

    Copy the code

    Copy the code

)}} const Root = connect(function(state) {return state; })(PageContainer); Reactdom.render (, document.getelementByid ('container')) // Render React

For example, the reducer needs to be injected into the store through the import component.

Advantages of architecture

  1. Component references are simple.
  2. The separation between the presentation and data components achieves low coupling, while the higher-order components that connect the two achieve high cohesion.
  3. All by TNPM management, module management is convenient.
  4. Even if you use a different data management architecture, you can use presentation components directly.

Some problems to be solved

  1. Common CSS cannot be managed and new build tools need to be introduced
  2. Development and debugging is not convenient, can not independently develop a component
  3. The component document is missing.
  4. Lack of test cases, component reliability cannot be guaranteed after iteration.