[To] React best practices--things that React didn't tell you, but very important.

Source: Internet
Author: User
Tags jquery library



For many react novices, the resources available online are mostly simple tutorial that teach you how to use react, but don't tell you how to gracefully organize and write react code in real-world projects. Google search Chinese "React best practices" found that the first two pages are almost all the same translation of foreign articles ... So I summed up my past that project use React trampled some pits, also collated some other people's views, hoping to some React users to help.


React and AJAX


React is only responsible for processing the view layer, which itself does not involve the network request/ajax, so here we need to consider two issues:


    • First, what technology is used to obtain data from the server;

    • Second, where the data obtained should be placed in the react component.


React officially provides a solution: Load Initial Data via AJAX



Using the Ajax method of jquery, the AJAX request is made in a component,componentDidMount()the data obtained is present in the component itselfstate, and the method is calledsetStateto update the UI. If the data is fetched asynchronously, thecomponentWillUnmountrequest is canceled in.



If the entire jquery library is introduced just to use jquery's AJAX approach, it is both a waste and an increase in the volume of the entire application. So, what other options do we have? In fact there are a lot of: fetch (), Fetch Polyfill, Axios ... One of the things that needs our attention most iswindow.fetch()that it is a concise, standardized JavaScript ajax API. Available in Chrome and Firefox, you can use fetch polyfill if you need to be compatible with other browsers.



React official documentation only tells us how to get data from the server side in a single component, but does not tell us which components of the data should be present in a complete real-world project, which, in the absence of specifications, can cause the entire project to become cluttered and difficult to maintain. Here are three more good practices:


1. All data requests and management are stored in a unique root component


Let the parent component/root component send all AJAX requests centrally, the data obtained from the server is stored uniformly in the state of the component, and the data is passed through props to the child components. This approach is primarily for small applications where the component tree is not very complex. The disadvantage is that when the hierarchy of the component tree becomes more and more, it is necessary to pass the data to the sub-components, which is difficult to write and the performance is not good.


2. Set up multiple container components to specifically handle data requests and management


In fact, it is similar to the first method, except that you set up multiple container components to handle data requests and state management. Here we need to differentiate between two different types of components, one is the display component (presentational component) and the other is the container component (container component). The display component itself does not have any state, all data is obtained from the container component and an AJAX request is sent in the container component. A more detailed description of both can be read under this article: presentational and Container components



A concrete example:



Suppose we need to show the user's name and avatar, first create a presentation component<UserProfile />that accepts two props:nameandprofileImage. There is no code for AJAX inside this component.



It then creates a container component<UserProfileContainer />that takes auserIdparameter, sends an AJAX request to get the data from the server to exist, and then passes it to thestateprops<UserProfile />component.


3. Use of redux or relay


Redux manages the state and data, Ajax gets the data from the server side, so obviously when we use the Redux, all the network requests should be given to redux to solve. Specifically, it should be placed in async Actions. If you use other types of flux libraries, the solution is similar to sending network requests in actions.



Relay is a library officially launched by Facebook. If we use it, we only need to declare the data that the component needs through GRAPHQL, relay will automatically download the data and pass the props down. But to use relay, you have to first have a GRAPHQL server ...


The organizational structure of a standard component
 
 
1 class definition
    1.1 constructor
        1.1.1 event handlers
    1.2 ‘component‘ lifecycle events
    1.3 getters
    1.4 render
2 defaultProps
3 proptypes


Example:


 
class Person extends React.Component {
  constructor (props) {
    super(props);

    this.state = { smiling: false };

    this.handleClick = () => {
      this.setState({smiling: !this.state.smiling});
    };
  }

  componentWillMount () {
    // add event listeners (Flux Store, WebSocket, document, etc.)
  },

  componentDidMount () {
    // React.getDOMNode()
  },

  componentWillUnmount () {
    // remove event listeners (Flux Store, WebSocket, document, etc.)
  },

  get smilingMessage () {
    return (this.state.smiling) ? "is smiling" : "";
  }

  render () {
    return (
      <div onClick={this.handleClick}>
        {this.props.name} {this.smilingMessage}
      </div>
    );
  },
}

Person.defaultProps = {
  name: ‘Guest‘
};

Person.propTypes = {
  name: React.PropTypes.string
};


Source of the above sample code: Https://github.com/planningcenter/react-patterns#component-organization


Using Proptypes and Getdefaultprops ()
    1. Be sure to write proptypes, do not write for the sake of convenience

    2. If a props is not requied, be sure to set it in Getdefaultprops

      React.PropTypesIt is mainly used to verify that the props received by the component are the correct data type, and if it is not correct, the corresponding warning will appear in the console. For performance reasons, this API is only used in the development environment.


Basic methods of Use:


propTypes: {
    myArray: React.PropTypes.array,
    myBool: React.PropTypes.bool,
    myFunc: React.PropTypes.func,
    myNumber: React.PropTypes.number,
    myString: React.PropTypes.string,
     
     // You can chain any of the above with `isRequired` to make sure a warning
    // is shown if the prop isn‘t provided.
    requiredFunc: React.PropTypes.func.isRequired
}


What if we props not the above types, but the objects with complex structures? For example, the following:


 
{ text: ‘hello world‘,
  numbers: [5, 2, 7, 9],
}


Of course, we can use it directlyReact.PropTypes.object, but we can't verify the data inside the object.


 
 
propTypes: {
  myObject: React.PropTypes.object,
}


Advanced methods of Use:shape()andarrayOf()


 
propTypes: { myObject: React.PropTypes.shape({
    text: React.PropTypes.string,
    numbers: React.PropTypes.arrayOf(React.PropTypes.number),
  })
}


The following is a more complex props:


[
  { name: ‘Zachary He‘, age: 13, married: true,
  },
  { name: ‘Alice Yo‘, name: 17,
  },
  { name: ‘Jonyu Me‘, age: 20, married: false,
  }
]


In general, it should be easy to write:


 
propTypes: { myArray: React.PropTypes.arrayOf(
        React.propTypes.shape({
            name: React.propTypes.string.isRequired,
            age: React.propTypes.number.isRequired,
            married: React.propTypes.bool
        })
    )
}
Give the calculation and condition judgment torender()Method Bar 1. Props cannot appear in the state of a component
 
// BAD:
  constructor (props) { this.state = { fullName: `${props.firstName} ${props.lastName}`
    };
  }

  render () { var fullName = this.state.fullName; return (
      <div>
        <h2>{fullName}</h2>
      </div>
    );
  }
// GOOD: 
render () { var fullName = `${this.props.firstName} ${this.props.lastName}`;
}


Of course, complex display logic should also avoid being stacked in render (), because that could result in the entire render () method becoming bloated and not graceful. We can move some complex logic out of the helper function.


 
// GOOD: helper function
renderFullName () { return `${this.props.firstName} ${this.props.lastName}`;
}

render () { var fullName = this.renderFullName();
}
2. Keep the state simple and do not show the calculated state
 
// WRONG:
  constructor (props) { this.state = {
      listItems: [1, 2, 3, 4, 5, 6],
      itemsNum: this.state.listItems.length
    };
  }
  render() { return (
          <div>
              <span>{this.state.itemsNum}</span>
          </div>
      )
  }
// Right:
render () { var itemsNum = this.state.listItems.length;
}

3. You can use the ternary judge, you do not need if, directly placed in the render ()
// BAD: 
renderSmilingStatement () { if (this.state.isSmiling) { return <span>is smiling</span>;
    }else { return ‘‘;
    }
},

render () { return <div>{this.props.name}{this.renderSmilingStatement()}</div>;
}
// GOOD: 
render () { return (
    <div>
      {this.props.name}
      {(this.state.smiling)
        ? <span>is smiling</span>
        : null
      }
    </div>
  );
}

4. The Boolean value can not be done, give iife.


immediately-invoked function expression


 
return (
  <section>
    <h1>Color</h1>
    <h3>Name</h3>
    <p>{this.state.color || "white"}</p>
    <h3>Hex</h3>
    <p>
      {(() => { switch (this.state.color) { case "red": return "#FF0000"; case "green": return "#00FF00"; case "blue": return "#0000FF"; default: return "#FFFFFF";
        }
      })()}
    </p>
  </section>
);
5. Do not write display logic incomponentWillReceivePropsOrcomponentWillMount, move them all to render (). How to handle classNames1 dynamically. Using Boolean values
// BAD:
constructor () {
    this.state = {
      classes: []
    };
  }

  handleClick () {
    var classes = this.state.classes;
    var index = classes.indexOf(‘active‘); if (index != -1) {
      classes.splice(index, 1);
    } else {
      classes.push(‘active‘);
    }

    this.setState({ classes: classes });
  } 
// GOOD:
  constructor () { this.state = {
      isActive: false
    };
  }

  handleClick () { this.setState({ isActive: !this.state.isActive });
  }

2. Use classnames this gadget to stitch Classnames:
  
// BEFORE: var Button = React.createClass({
  render () { var btnClass = ‘btn‘; if (this.state.isPressed) btnClass += ‘ btn-pressed‘; else if (this.state.isHovered) btnClass += ‘ btn-over‘; return <button className={btnClass}>{this.props.label}</button>;
  }
});
// AFTER: var classNames = require(‘classnames‘); var Button = React.createClass({
  render () { var btnClass = classNames({ ‘btn‘: true, ‘btn-pressed‘: this.state.isPressed, ‘btn-over‘: !this.state.isPressed && this.state.isHovered
    }); return <button className={btnClass}>{this.props.label}</button>;
  }
});


Not to be continued ...



[To] React best practices--things that React didn't tell you, but very important.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.