当前位置:网站首页>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 .
版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢
边栏推荐
- htmlcss
- I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
- EOS创始人BM: UE,UBI,URI有什么区别?
- Group count - word length
- 一篇文章带你了解CSS3 背景知识
- xmppmini 專案詳解:一步一步從原理跟我學實用 xmpp 技術開發 4.字串解碼祕笈與訊息包
- git rebase的時候捅婁子了,怎麼辦?線上等……
- TRON智能钱包PHP开发包【零TRX归集】
- Use of vuepress
- The choice of enterprise database is usually decided by the system architect - the newstack
猜你喜欢
JVM memory area and garbage collection
It's so embarrassing, fans broke ten thousand, used for a year!
在大规模 Kubernetes 集群上实现高 SLO 的方法
ES6学习笔记(二):教你玩转类的继承和类的对象
How to encapsulate distributed locks more elegantly
EOS创始人BM: UE,UBI,URI有什么区别?
Filecoin主网上线以来Filecoin矿机扇区密封到底是什么意思
vue任意关系组件通信与跨组件监听状态 vue-communication
從小公司進入大廠,我都做對了哪些事?
Summary of common algorithms of linked list
随机推荐
Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
Python自动化测试学习哪些知识?
Character string and memory operation function in C language
(2)ASP.NET Core3.1 Ocelot路由
What problems can clean architecture solve? - jbogard
至联云分享:IPFS/Filecoin值不值得投资?
采购供应商系统是什么?采购供应商管理平台解决方案
5.4 static resource mapping
使用 Iceberg on Kubernetes 打造新一代云原生数据湖
OPTIMIZER_ Trace details
Relationship between business policies, business rules, business processes and business master data - modern analysis
The practice of the architecture of Internet public opinion system
向北京集结!OpenI/O 2020启智开发者大会进入倒计时
做外包真的很难,身为外包的我也无奈叹息。
一篇文章带你了解CSS3图片边框
Tool class under JUC package, its name is locksupport! Did you make it?
From zero learning artificial intelligence, open the road of career planning!
ES6学习笔记(二):教你玩转类的继承和类的对象
如何将数据变成资产?吸引数据科学家
Natural language processing - wrong word recognition (based on Python) kenlm, pycorrector