当前位置:网站首页>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 .
版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢
边栏推荐
- 每个前端工程师都应该懂的前端性能优化总结:
- 数据产品不就是报表吗?大错特错!这分类里有大学问
- 從小公司進入大廠,我都做對了哪些事?
- ES6学习笔记(四):教你轻松搞懂ES6的新增语法
- Using consult to realize service discovery: instance ID customization
- JVM memory area and garbage collection
- 2019年的一个小目标,成为csdn的博客专家,纪念一下
- 前端工程师需要懂的前端面试题(c s s方面)总结(二)
- Existence judgment in structured data
- 向北京集结!OpenI/O 2020启智开发者大会进入倒计时
猜你喜欢
The difference between Es5 class and ES6 class
It's so embarrassing, fans broke ten thousand, used for a year!
采购供应商系统是什么?采购供应商管理平台解决方案
Architecture article collection
带你学习ES5中新增的方法
Face to face Manual Chapter 16: explanation and implementation of fair lock of code peasant association lock and reentrantlock
一篇文章带你了解CSS3圆角知识
[JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
Thoughts on interview of Ali CCO project team
一篇文章带你了解CSS对齐方式
随机推荐
Working principle of gradient descent algorithm in machine learning
Keyboard entry lottery random draw
Use of vuepress
From zero learning artificial intelligence, open the road of career planning!
I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
ES6学习笔记(二):教你玩转类的继承和类的对象
Examples of unconventional aggregation
hadoop 命令总结
至联云解析:IPFS/Filecoin挖矿为什么这么难?
High availability cluster deployment of jumpserver: (6) deployment of SSH agent module Koko and implementation of system service management
vue任意关系组件通信与跨组件监听状态 vue-communication
CCR炒币机器人:“比特币”数字货币的大佬,你不得不了解的知识
Word segmentation, naming subject recognition, part of speech and grammatical analysis in natural language processing
It's so embarrassing, fans broke ten thousand, used for a year!
Did you blog today?
ES6学习笔记(五):轻松了解ES6的内置扩展对象
The difference between Es5 class and ES6 class
怎么理解Python迭代器与生成器?
一篇文章带你了解CSS 分页实例
Let the front-end siege division develop independently from the back-end: Mock.js