If you feel ok, please like more, encourage me to write more wonderful article 🙏.

If you have any questions, feel free to comment in the comments section

TL; DR

  • preface
  • Conventional componentization thinking
  • Hooks components
  • Unconventional components (have strange effects, focus on this)

preface

In some of my articles, either written by myself or translated from the blogs of good foreign developers. One of the main lines is to understand the JS foundation, to carry out front-end modular practice. In particular, React and Vue, which are popular front-end frameworks, advocate the separation of page components. This is actually the design idea of MVVM.

In today’s React project development, we’ll talk about how to implement componentization in real projects, or how to implement high-order logic administration.

The following content is used in my daily development and has been practiced (if you have better ideas, you can also leave a message to discuss, after all, everyone has more or less cognitive differences on an event).

I believe that practice is the source of real knowledge. Without practice, we have no right to speak

Conventional componentization thinking

The title here is general, because what this space is talking about is also the general solution that React official advocates after all. (Hooks, for example, because the API is relatively new and unfamiliar to some development, and affected by the React version of the company, it only stays at the theoretical stage. I will include Hooks separately 🌰)

If you’ve read the React website often, ADVANCED GUIDES have identified two ways to implement logic use: HOC and Render Props.

So let’s give a brief introduction.

HOC

Here’s the official explanation:

A higher-order component (HOC) is an advanced technique in React for reusing component logic.

In fact, if the JS advanced function has had an understanding of children’s shoes, see this will not feel very strange. HOC, on the other hand, mimics high-level functions to refine common logic. So as to achieve the effect of code reuse.

To dig deeper, higher-order functions can take functions as arguments and return functions at the same time.

function hof(f){
    let name="North Chen";
    return f(name);
}

function f(name){
    console.log(`${name}A dear fellow! `)}Copy the code

See this is kind of a closure. That is, the wrapped function has access to the variables defined in hOF.

If you want to have a deeper understanding of closures, scope can refer to

  1. Take a look at Closures
  2. Take you into the world of JS Scope

This is a little bit off track. Let’s get down to business.

const EnhancedComponent = higherOrderComponent(WrappedComponent);
Copy the code

This is a summary of a simple formula for HOC. I think hof is pretty familiar with this.

Talk is cheap,show your the code

functionEnhancedComponent(WrappedComponent){// We can define some common arguments and logic herereturnClass extends React.Component{// state={// defines some public property names:'north Chen'
       }

    componentDidMount() {// do some data initialization}componentWillUnmount() {// Unbinding for some registered events such as polling events}handleChange() {// Custom event handling}renderConst {name} = this.state; const {name} = this.state;return<WrappedComponent parentData={name} // Pass some common data to {... This. Props} // simple pass to />; }}}Copy the code

This is a simple example of HOC. If you want to have a deeper understanding of HOC can refer to

  1. React-hoc (this is something I wrote earlier, maybe a little Low)

Render Props

This is also a common way to reuse logic.

To summarize, there is a property in a component property, and that property is a function that returns a component.

<RenderProps renderRegion={(value)=><CommonConponenet value={value}/>}
Copy the code

Explain a little bit that the RenderProps component contains some common logic and data, which is exactly what CommonConponenet needs.

Talk is cheap,show your the code

class RenderProps extends React.Component{
    state={
        name:'north Chen'Render (const {name} = this.state;return(<section> <> //RenderProps own page structure </> // If too much data is passed in, you can use an object to wrap the data {this.props. RenderRegion (name)} </section>))}Copy the code

Presumably, everyone in the peacetime development, more or less all use these more conventional ways.

The above is just a brief introduction. In fact, the focus of this article is on the following unconventional operations.

Hooks components

I’m sure you’ve been looking through some of the technical documentation, and there are a lot of references to Hooks. This article is not wordy, and today is ready to talk about some unconventional operations. If you really want to know more, please refer to my translation of a simple application of Hooks.

  1. React-hooks learn about this

First, to be clear, hooks are extended to function components. Is to allow function components to enjoy the state/ life cycle as well.

To give you an application scenario, there is a component, there is a timing function, need a timer, temporarily positioned within 15 minutes of the timer runs out, and after the timer is completed for additional operations.

Through the above requirements, let’s analyze a wave.

  1. There is a timer function, which must be triggered when the component is initialized. After triggering the timer, the timer will open an additional thread for data processing.
  2. Every time the time changes, it needs to be displayed on the page
  3. We need to monitor whether the timer reaches the requirement (additional operation is required after 15min).
  4. Trigger extra action
  5. If the component is destroyed within 15 minutes, the timer needs to be destroyed

Talk is cheap,show your the code

import React,{useState,useEffect} from 'react';
functionTest(props){// Const {name}=props; const [msg,setMsg] = useState("Valid time of QR code: 15 minutes 00 seconds");
    lettimer, maxtime = 15 * 60; UseEffect (()=>{timer = //1 Initializes a timer (while the component is initializing)setInterval(() => {
      if (maxtime >= 0) {
        let minutes = Math.floor(maxtime / 60);
        let seconds = Math.floor(maxtime % 60);
        let msg = "Qr code valid time:" + minutes + "Points" + seconds + "Seconds"; --maxtime; //2. Define a state variable for page displaysetMsg(msg)
      } else{ clearInterval(timer); // If time runs out under normal circumstances, do additional operations //3.return()=>{ clearInterval(timer); }},[])// Why is the second argument needed here? You can refer to the link I just gave to find the reasonfunction stopTimer(){
        clearInterval(timer);
    }
    
    return(< section > < Button onClick = {() = > {enclosing stopTimer ()}} > stop timing < / Button > {mag} < / section >)}Copy the code

Unconventional component

This part, is my usual project development, sometimes used component packaging ideas, if you have good opinions and suggestions, can discuss with each other. In short, the purpose of achieving is to take its essence, to its trough meal.

Because the UI library used in project development is Antd, some usage methods are also based on its usage rules to use.

RandomKey

If you are in the React project, render some components, such as Li, by iterating through an array. There will be a warning on the console if you don’t add a key. This key is also a hidden property in React. It’s for the Diff algorithm.

However, there are some scenarios, for example, some pop-ups, which require users to fill in some information, and some users cancel the operation when filling in, so the normal processing method is to traverse and recover data by comparing the original information.

On the other hand, if you can listen for user cancellations at the component call, that’s convenient, but it’s a no-choice option. RandomKey.

<Test key={Math.random() />}
Copy the code

The State components

This noun is my own, arbitrarily named, if you feel a good name, let me know in the comments section.

If you are in a React development project, you may have planned well in the early stage and wrote the page step by step, but, but, but, you can’t stand it. The product keeps changing the requirements every day, and you find that you can’t understand what you planned before.

Or maybe your boss asks you to maintain code written by someone else, add a new requirement, and when you see code written by someone else, your heart cools. Is this really human-readable code, regardless of whether logic is responsible, all the functionality of a page is in one file. (Stacking is not an overstatement; I’ve seen people write 1000 lines of code and 20 + states on a page).

For example, now we have the following component, need to add a popover, and add a popover, let’s simply count the required variables

  1. visibleForXX
  2. valueXX

For the time being do the least

Class StateComponent extends React.Component{state={visibleForXX:false,
        valueXX:'north Chen'. } handleVisible=(visible)=>{ this.setState({ visibleForXX:visible }) } render( const {visibleForXX,valueXX}= this.state;  const {valueFromPorpsA,valueFromPorpsB} = this.props;return<Button onClick=(()=>this.handleVisible()true</Button> <Button onClick=(()=> this.handlevisible (false</Button> {visibleForXX? <Modal visible={visibleForXX} valueXX={valueXX} valueFromPorpsA={valueFromPorpsA} //.... If logic is responsible, there might be more > //bala Bala big push </Modal> :null} </section>))}Copy the code

What’s wrong with that? There’s nothing wrong with that. Does it work? Yes. Can you deliver? Yes. Can you review it? Review has nothing to do with code quality. Can the guy in the back who maintains your code ask after your relatives? I feel like I can, too.

Also, did you notice that although I wrote the code with the purpose of using deconstruction, I did a scope-chain lookup every time I rendered the component regardless of whether it was related to it or not? Is it necessary? I haven’t.

What’s the solution? Some people say, well, you wouldn’t take a component out. Yes, this new feature is usually a component if I develop it as I normally would. However, the above Modal code is removed, in fact, there will be every render scope chain lookup problem.

Well, there’s another way to think about it.

Just serve it.

import Modal from '.. / a file path, or alias'Class StateComponent extends React.Component{state={// 7-10 parameters are ignored here ModalNode:null} handleClick=()=>{const {valueFromPorpsA,valueFromPorpsB} = this.props; this.setState( ModalNode:<Modal visible={visibleForXX} valueXX={valueXX} valueFromPorpsA={valueFromPorpsA} //.... />)} render(const {ModalNode}= this.state;return</Button onClick=(this.handleclick)> </Button> {ModalNode? ModalNode :null } </section> ) ) }Copy the code

Move the components around. He smells good. Do relevant things with the most intensive code. While it is possible that the person receiving your code may be abusive, wait for him to replace a simple parameter. You don’t have to navigate 1,000 lines of code.

The above example, just briefly said the idea, but certainly can be implemented, due to the space problem, NOT CV smelly and long code.

Self-control shows implicit Modal

Have you met such a requirement that you need to add a popover in a page, and this new task is to give you 叒 yi?

You jump at it and see what needs to be added, another stack of XX code. (You know what I mean)

Let’s move on to the conditions that regular Modal(once you’ve encapsulated Modal as a component) has (what you need to prepare at the invocation)

  1. visible
  2. this.handleVisible(false)
  3. This.handleok (there may be additional operations here)

The list is the simplest, and there may be more complicated. This.handlevisible (false) controls Modal closing.

And then you go back to bala, bala. It’s ok if you have 1 or 2 modal on a page, but if you have 4 or 5 modal, you still use this way, oh my God, congratulations on being a premium member of the CV club.

I can make two points, weakly and humbly

  1. willModalThe shell encapsulates the components that you are only responsible forcontentThe writing of
  2. encapsulatedModalControl the explicit and implicit by yourself

Let’s focus on 2, because this is the home of 2.

Talk is cheap,show your the code

Component invocation, you will find that as long as the corresponding component is introduced and a child node is defined, you can implement a control explicit and implicit component.

<OperatingModal> <Button> Click </Button> </OperatingModal>Copy the code

Modal is a simple implementation idea

import React from 'react';
import { Modal } from 'antd';
export class OperatingModal extends React.Component {
    static getDerivedStateFromProps(nextProps, state) {
        if ('visibleFromParent' innextProps && nextProps.visibleFromParent && ! state.visible) {return {
                visible: nextProps.visibleFromParent
            }
        }
        return null;
    }
    state = {
        visible: false} handleVisible = (visible) => { this.setState({ visible: visible }); } handleOk = (secondNode) => {renderFooter = () => {const {footer, footerPosition} = this.let footerNode = footer;
        if(footer ! = null) {letfooterChidren = footerNode.props.children; footerNode = <div > {footerChidren.length > 1 ? </ react. Fragment> : footer} </div>}return footerNode;

    }

    render() {
        const { title, children, content, width, closable, zIndex } = this.props;
        const { visible } = this.state;
        return (
            <section>
                {children ?
                    React.cloneElement(children, { onClick: () => this.handleVisible(true)}) : null} < Modal / / general configuration > {content} < / Modal > < section >)}} OperatingModal. DefaultProps = {title:'tip',
    content: 'I am content'Footer: null, visibleFromParent:false,
    width: 300,
    closable: true,
    footerPosition: 'center',
    zIndex: 1000,
}

Copy the code

This is my simple version, so if you happen to use ANTD, you can try it out.

One thing to note here is that we use a React property called React. CloneElement. Specific API explanation can refer to the official website.

You should use Modal in form submission

This example is based on an upgraded version of 2(explicit implicit self control Modal) and provides only one idea. The main code is as follows.

This component has the following functions:

  1. Form forms and non-form forms
  2. Show hidden self-control
  3. Anti-duplicate submission
  4. After the from submission, you can obtain the interface result and perform other operations
  5. The parent component can also call show hide
  6. .

Component invocation

<AdaptationFromModal> <From.Item> //..... </From.Item> // many From.Item </AdaptationFromModal>Copy the code

General idea of component implementation

import React, { Component } from 'react';
import {
  Modal, Form, Button, message,
} from 'antd';
import throttle from 'lodash.throttle';

class AdaptationFromModal extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      visible: false,
      isSubmitLoading: false,
      randomKey: 1,
    };
    this.handleOK = this.handleOK.bind(this);
    this.handleOKThrottled = throttle(this.handleOK, 4000);
  }

  componentWillUnmount() {
    this.handleOKThrottled.cancel();
  }

  renderFormCotent = () => {
    letformContentNode = null; const { formItemLayout } = this.props; FormContentNode = (<Form > // loop renderCotent </Form>);return formContentNode;
  }

  renderNormalContent = () => {
    letnormalContentNode = null; NormalContentNode = this.props. RenderCotent (// Can throw the component value);return normalContentNode;
  }

  webpackModalVisibleStatus = (visible = false) => {this.setState({visible: visible,}, () => {// handle relevant code according to different visible}); }handleOK() {
    const { isIncludeForm, callbackForOK, callbackForOKAfter } = this.props;
    this.setState({
      isSubmitLoading: true});if}} renderFooter = () => {const {isHasPersonFooter, defineFooterNode, callbackForOK, callbackForOKAfter, } = this.props; const { isSubmitLoading } = this.state;let footerNode = null;
    if (isHasPersonFooter) {
      if(defineFooterNode ! == null) {footerNode = defineFooterNode(// here you can throw the value inside the component); }}else{footerNode = (// regular render); }return footerNode;
  }


  render() {
    const { visible, randomKey } = this.state;
    const {
      width, isIncludeForm, title, children, style,
    } = this.props;
    return (
      <section style={style || {}}>
        {children
          ? React.cloneElement(children, { onClick: () => this.webpackModalVisibleStatus(true) }) : null} {visible ? (<Modal // Regular Modal configuration > {isIncludeForm? this.renderFormCotent() : this.renderNormalContent() } </Modal> ) : null} </section> ); } } AdaptationFromModal.defaultProps = { title:'xxx', //
  width: 600,
  isIncludeForm: true,
  isHasPersonFooter: falseFormItemLayout: {labelCol: {span: 6}, wrapperCol: {span: 14},}, style: undefined, };export default Form.create()(AdaptationFromModal);

Copy the code

Antd Form joke

Some companies may have forms in their business, and similar functions are simple form processing. However, ANTD requires a lot of redundant configuration for form processing. As follows:

 <Form layout="inline" onSubmit={this.handleSubmit}>
        <Form.Item validateStatus={usernameError ? 'error' : ' '} help={usernameError || ' '}>
          {getFieldDecorator('username', {
            rules: [{ required: true, message: 'Please input your username! ' }],
          })(
            <Input
              prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
              placeholder="Username"
            />,
          )}
        </Form.Item>
        <Form.Item validateStatus={passwordError ? 'error' : ' '} help={passwordError || ' '}>
          {getFieldDecorator('password', {
            rules: [{ required: true, message: 'Please input your Password! ' }],
          })(
            <Input
              prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)'/ >}}}type="password"
              placeholder="Password"
            />,
          )}
        </Form.Item>
      </Form>
Copy the code

For example, some form. Item, getFieldDecorator things look like an eyesore. Is there a way to simply configure some of the components required by the page, and these processes in a shell?

 <SearchBoxFactory
        callBackFetchTableList={this.callBackFetchTableList}
        callBackClearSearchCondition={this.callBackClearSearchCondition}
      >
        <Input
          placeholder={'Please enter your name'}
          formobj={{
            apiField: 'XXA', initialValue: ' ', maxLength: 50, label: 'north Chen',
          }}
        />
        <Input
          placeholder={'Please enter your gender'}
          formobj={{
            apiField: 'XXB', initialValue: ' ', maxLength: 50, label: 'the south stand',
          }}
        />
        <Select
          style={{ width: 120 }}
          formobj={{
            apiField: 'status', initialValue: '1',
          }}
        >
          <Option value="1"Am I handsome? </Option> <Option value="2"Word-wrap: break-word! Important; "> < p style =" max-width: 100%; </Option> </Select> </SearchBoxFactory>Copy the code

It doesn’t taste good to him that way. I just wanted to know if you smelled good.

conclusion

In fact, componentization in React is a programming idea. I think lazy people can really appreciate its charm, because lazy people can think of faster, higher, and stronger ways to make themselves write code.

This is also a programming habit and approach. Use the shortest time, write the least code, do the most beautiful code.

I hope I’ve been helpful. If you see something you don’t understand, you can leave a comment in the comments section. If you’re not having a good time. It’s okay. These things, there’s a lot of them.

In fact, every day is noisy componentization, componentization, componentization is in the actual development project, in solving the actual business, the inspiration. His main aim is to solve practical problems, not to insulate himself.