当前位置:网站首页>Our best practices for writing react components
Our best practices for writing react components
2020-11-06 01:23:00 【:::::::】
Rigid contact React
When , In one tutorial after another, I saw many functions for writing components , Even then React
The framework is quite mature , But there is no fixed rule for us to write code .
In the past year , We are constantly improving our approach , Until you are satisfied .
This article will list our own best practices in use , Whether you're a beginner or an experienced developer , We all hope this article will help you .
Before the start , Here are a few :
- We use ES6/ES7
- If you can't tell a page component from a container component , Recommended reading This article
- If there is a better opinion or suggestion , Please tell me in the comments area , thank you
be based on Class The components of
be based on Class The components of are stateful , Whether it contains no functions , We all use as little as possible . But it also has its uses .
Now let's write our components line by line :
Import CSS
import React, { Component } from 'react' import { observer } from 'mobx-react' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css'
I like CSS in Javascript
, But the concept is still relatively new , There is no mature solution now , So we refer to... In each component CSS
initialization State
import React, { Component } from 'react' import { observer } from 'mobx-react' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { state = { expanded: false }
Of course, you can also choose to initialize in the constructor , But we think this way is clearer .
Of course, it will guarantee that Class It is exported by default .
propTypes and defaultProps
import React, { Component } from 'react' import { observer } from 'mobx-react' import { string, object } from 'prop-types' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { state = { expanded: false } static propTypes = { model: object.isRequired, title: string } static defaultProps = { model: { id: 0 }, title: 'Your Name' }
propTypes and defaultProps It's a static property , Write them at the top of the component as much as possible , For other developers to read .
If you use React 15.3.0
Or later , Use prop-types Instead of React.PropTypes
All components must declare propTypes
function
import React, { Component } from 'react' import { observer } from 'mobx-react' import { string, object } from 'prop-types' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { state = { expanded: false } static propTypes = { model: object.isRequired, title: string } static defaultProps = { model: { id: 0 }, title: 'Your Name' } handleSubmit = (e) => { e.preventDefault() this.props.model.save() } handleNameChange = (e) => { this.props.model.changeName(e.target.value) } handleExpand = (e) => { e.preventDefault() this.setState({ expanded: !this.state.expanded }) }
Using a Class Components of , When you pass functions to subcomponents , Make sure they have the right one this
, It is usually implemented in this form this.handleSubmit.bind(this)
But if you use the arrow function , There is no need to bind(this)
by setState Transfer function
This is what we did in the example above :
this.setState({ expanded: !this.state.expanded })
Here is a setState Little knowledge —— It's asynchronous , To guarantee performance ,React
It will be modified in batches state, therefore state It won't be calling setState Immediately after that
This means you can't rely on the current state , Because you don't know what the current state is
Here's a solution —— Transfer function to setState,React
Will put the last state prevState
Pass it on to you
this.setState(prevState => ({ expanded: !prevState.expanded }))
deconstruction Props
import React, { Component } from 'react' import { observer } from 'mobx-react' import { string, object } from 'prop-types' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { state = { expanded: false } static propTypes = { model: object.isRequired, title: string } static defaultProps = { model: { id: 0 }, title: 'Your Name' } handleSubmit = (e) => { e.preventDefault() this.props.model.save() } handleNameChange = (e) => { this.props.model.changeName(e.target.value) } handleExpand = (e) => { e.preventDefault() this.setState(prevState => ({ expanded: !prevState.expanded })) } render() { const { model, title } = this.props return ( <ExpandableForm onSubmit={this.handleSubmit} expanded={this.state.expanded} onExpand={this.handleExpand}> <div> <h1>{title}</h1> <input type="text" value={model.name} onChange={this.handleNameChange} placeholder="Your Name"/> </div> </ExpandableForm> ) } }
Like the example above , Every prop All in one line
Decorator (Decorators)
@observer export default class ProfileContainer extends Component {
If you use something like mobx The library of , You can decorate your Class Components
Modify functional components to use decorators It's flexible and readable
If you don't want to use decorators , You can do that :
class ProfileContainer extends Component { // Component code } export default observer(ProfileContainer)
Closure
Avoid passing new closures to subcomponents as noted below :
<input type="text" value={model.name} // onChange={(e) => { model.name = e.target.value }} // ^ Not this. Use the below: onChange={this.handleChange} placeholder="Your Name"/>
The advantage of this approach is that every time render, It doesn't recreate a function , No additional performance loss .
Here's the complete component :
import React, { Component } from 'react' import { observer } from 'mobx-react' import { string, object } from 'prop-types' // Separate local imports from dependencies import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' // Use decorators if needed @observer export default class ProfileContainer extends Component { state = { expanded: false } // Initialize state here (ES7) or in a constructor method (ES6) // Declare propTypes as static properties as early as possible static propTypes = { model: object.isRequired, title: string } // Default props below propTypes static defaultProps = { model: { id: 0 }, title: 'Your Name' } // Use fat arrow functions for methods to preserve context (this will thus be the component instance) handleSubmit = (e) => { e.preventDefault() this.props.model.save() } handleNameChange = (e) => { this.props.model.name = e.target.value } handleExpand = (e) => { e.preventDefault() this.setState(prevState => ({ expanded: !prevState.expanded })) } render() { // Destructure props for readability const { model, title } = this.props return ( <ExpandableForm onSubmit={this.handleSubmit} expanded={this.state.expanded} onExpand={this.handleExpand}> // Newline props if there are more than two <div> <h1>{title}</h1> <input type="text" value={model.name} // onChange={(e) => { model.name = e.target.value }} // Avoid creating new closures in the render method- use methods like below onChange={this.handleNameChange} placeholder="Your Name"/> </div> </ExpandableForm> ) } }
Functional component
These components have no states and functions , They are pure , It's very easy to read , Use them as much as possible .
propTypes
import React from 'react' import { observer } from 'mobx-react' import { func, bool } from 'prop-types' import './styles/Form.css' ExpandableForm.propTypes = { onSubmit: func.isRequired, expanded: bool } // Component declaration
Here we put propTypes Let me write it first , It will be immediately visible to the component , This is due to JavaScript Of Function enhancement
deconstruction Props and defaultProps
import React from 'react' import { observer } from 'mobx-react' import { func, bool } from 'prop-types' import './styles/Form.css' ExpandableForm.propTypes = { onSubmit: func.isRequired, expanded: bool, onExpand: func.isRequired } function ExpandableForm(props) { const formStyle = props.expanded ? {height: 'auto'} : {height: 0} return ( <form style={formStyle} onSubmit={props.onSubmit}> {props.children} <button onClick={props.onExpand}>Expand</button> </form> ) }
Our component is a function , We got his props Is to get the parameter value of the function , We can use it directly ES6
Deconstruction of :
import React from 'react' import { observer } from 'mobx-react' import { func, bool } from 'prop-types' import './styles/Form.css' ExpandableForm.propTypes = { onSubmit: func.isRequired, expanded: bool, onExpand: func.isRequired } function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) { const formStyle = expanded ? {height: 'auto'} : {height: 0} return ( <form style={formStyle} onSubmit={onSubmit}> {children} <button onClick={onExpand}>Expand</button> </form> ) }
We can also use default parameter values to set defaultProps
, Just like up here expanded = false
Avoid using the following ES6 grammar :
const ExpandableForm = ({ onExpand, expanded, children }) => {
It seems to be very early ( forced ) Into the ( grid ), But this function is anonymous .
If your Babel Set up correctly , This anonymous function won't be a problem —— But if not , Any errors will be displayed in << anonymous >>
in , This is very bad for debugging .
Wrapping
Cannot be used in functional components decorators
, You just pass it to the past as an argument
import React from 'react' import { observer } from 'mobx-react' import { func, bool } from 'prop-types' import './styles/Form.css' ExpandableForm.propTypes = { onSubmit: func.isRequired, expanded: bool, onExpand: func.isRequired } function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) { const formStyle = expanded ? {height: 'auto'} : {height: 0} return ( <form style={formStyle} onSubmit={onSubmit}> {children} <button onClick={onExpand}>Expand</button> </form> ) } export default observer(ExpandableForm)
Here's the complete component :
import React from 'react' import { observer } from 'mobx-react' import { func, bool } from 'prop-types' // Separate local imports from dependencies import './styles/Form.css' // Declare propTypes here, before the component (taking advantage of JS function hoisting) // You want these to be as visible as possible ExpandableForm.propTypes = { onSubmit: func.isRequired, expanded: bool, onExpand: func.isRequired } // Destructure props like so, and use default arguments as a way of setting defaultProps function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) { const formStyle = expanded ? { height: 'auto' } : { height: 0 } return ( <form style={formStyle} onSubmit={onSubmit}> {children} <button onClick={onExpand}>Expand</button> </form> ) } // Wrap the component instead of decorating it export default observer(ExpandableForm)
JSX Condition judgment in
You may have complex conditional statements , But you should avoid the following :
Nested ternary expressions are not a good way , It's so hard to read
There are libraries that can solve this problem (jsx-control-statements), But we didn't introduce any other libraries , This is how we solved it :
We used Immediate execution function Write the conditional sentence in it , Although this may lead to performance degradation , But in most cases , Its negative impact is still less than poor readability .
Of course, if the components are detailed enough , You may not use such complex conditional judgments .
Besides , If you only render components in one expression , Avoid this :
True!
: } title="" data-original-title=" Copy ">
{ isTrue ? <p>True!</p> : <none/> }
You can use short circuit syntax :
True!
} " title="" data-original-title=" Copy ">
{ isTrue && <p>True!</p> }
summary
Does this article help you ? Please give your comments and suggestions in the comments section , Thank you for reading !
This article starts with my Personal blog , I also recommend a scaffold I wrote a while ago parcel-typescript-react-boilerplate, Please give your comments and suggestions , Learn from each other . Shamelessly ask for a star , thank you ~~!
Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .
版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢
边栏推荐
- Keyboard entry lottery random draw
- Flink的DataSource三部曲之二:内置connector
- Python download module to accelerate the implementation of recording
- 速看!互联网、电商离线大数据分析最佳实践!(附网盘链接)
- What is the side effect free method? How to name it? - Mario
- [JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
- 基於MVC的RESTFul風格API實戰
- Group count - word length
- 比特币一度突破14000美元,即将面临美国大选考验
- How long does it take you to work out an object-oriented programming interview question from Ali school?
猜你喜欢
Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
人工智能学什么课程?它将替代人类工作?
前端工程师需要懂的前端面试题(c s s方面)总结(二)
每个前端工程师都应该懂的前端性能优化总结:
一篇文章带你了解HTML表格及其主要属性介绍
The difference between Es5 class and ES6 class
一篇文章带你了解CSS3图片边框
Just now, I popularized two unique skills of login to Xuemei
How to select the evaluation index of classification model
TRON智能钱包PHP开发包【零TRX归集】
随机推荐
5.5 controlleradvice notes - SSM in depth analysis and project practice
小程序入门到精通(二):了解小程序开发4个重要文件
Natural language processing - wrong word recognition (based on Python) kenlm, pycorrector
How to select the evaluation index of classification model
Did you blog today?
Linked blocking Queue Analysis of blocking queue
Don't go! Here is a note: picture and text to explain AQS, let's have a look at the source code of AQS (long text)
Skywalking series blog 1 - install stand-alone skywalking
Using Es5 to realize the class of ES6
加速「全民直播」洪流,如何攻克延时、卡顿、高并发难题?
What problems can clean architecture solve? - jbogard
Vue 3 responsive Foundation
Subordination judgment in structured data
Skywalking series blog 2-skywalking using
PHPSHE 短信插件说明
Summary of common string algorithms
Natural language processing - BM25 commonly used in search
Summary of common algorithms of binary tree
6.5 request to view name translator (in-depth analysis of SSM and project practice)
采购供应商系统是什么?采购供应商管理平台解决方案