当前位置:网站首页>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 .
版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢
边栏推荐
- [JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
- Deep understanding of common methods of JS array
- 业内首发车道级导航背后——详解高精定位技术演进与场景应用
- ES6学习笔记(二):教你玩转类的继承和类的对象
- Polkadot series (2) -- detailed explanation of mixed consensus
- 6.1.1 handlermapping mapping processor (1) (in-depth analysis of SSM and project practice)
- 5.4 static resource mapping
- Real time data synchronization scheme based on Flink SQL CDC
- 人工智能学什么课程?它将替代人类工作?
- 一篇文章带你了解CSS 渐变知识
猜你喜欢

业内首发车道级导航背后——详解高精定位技术演进与场景应用

Word segmentation, naming subject recognition, part of speech and grammatical analysis in natural language processing

快快使用ModelArts,零基礎小白也能玩轉AI!

hadoop 命令总结

CCR炒币机器人:“比特币”数字货币的大佬,你不得不了解的知识

Just now, I popularized two unique skills of login to Xuemei

Can't be asked again! Reentrantlock source code, drawing a look together!

Windows 10 tensorflow (2) regression analysis of principles, deep learning framework (gradient descent method to solve regression parameters)
![[C / C + + 1] clion configuration and running C language](/img/5b/ba96ff4447b150f50560e5d47cb8d1.jpg)
[C / C + + 1] clion configuration and running C language

在大规模 Kubernetes 集群上实现高 SLO 的方法
随机推荐
TRON智能钱包PHP开发包【零TRX归集】
htmlcss
业内首发车道级导航背后——详解高精定位技术演进与场景应用
向北京集结!OpenI/O 2020启智开发者大会进入倒计时
带你学习ES5中新增的方法
前端基础牢记的一些操作-Github仓库管理
Save the file directly to Google drive and download it back ten times faster
快快使用ModelArts,零基础小白也能玩转AI!
6.5 request to view name translator (in-depth analysis of SSM and project practice)
[C / C + + 1] clion configuration and running C language
Common algorithm interview has been out! Machine learning algorithm interview - KDnuggets
vue-codemirror基本用法:实现搜索功能、代码折叠功能、获取编辑器值及时验证
What is the difference between data scientists and machine learning engineers? - kdnuggets
Filecoin主网上线以来Filecoin矿机扇区密封到底是什么意思
大数据应用的重要性体现在方方面面
做外包真的很难,身为外包的我也无奈叹息。
How do the general bottom buried points do?
ipfs正舵者Filecoin落地正当时 FIL币价格破千来了
The practice of the architecture of Internet public opinion system
多机器人行情共享解决方案