当前位置:网站首页>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 .
版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢
边栏推荐
- 钻石标准--Diamond Standard
- Relationship between business policies, business rules, business processes and business master data - modern analysis
- The choice of enterprise database is usually decided by the system architect - the newstack
- JVM memory area and garbage collection
- 小程序入门到精通(二):了解小程序开发4个重要文件
- What is the side effect free method? How to name it? - Mario
- Flink的DataSource三部曲之二:内置connector
- 带你学习ES5中新增的方法
- hadoop 命令总结
- 业内首发车道级导航背后——详解高精定位技术演进与场景应用
猜你喜欢
[JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
ES6学习笔记(四):教你轻松搞懂ES6的新增语法
钻石标准--Diamond Standard
Summary of common algorithms of linked list
How long does it take you to work out an object-oriented programming interview question from Ali school?
前端都应懂的入门基础-github基础
Existence judgment in structured data
Calculation script for time series data
Natural language processing - BM25 commonly used in search
Summary of common string algorithms
随机推荐
Computer TCP / IP interview 10 even asked, how many can you withstand?
JVM memory area and garbage collection
熬夜总结了报表自动化、数据可视化和挖掘的要点,和你想的不一样
比特币一度突破14000美元,即将面临美国大选考验
Filecoin的经济模型与未来价值是如何支撑FIL币价格破千的
從小公司進入大廠,我都做對了哪些事?
[JMeter] two ways to realize interface Association: regular representation extractor and JSON extractor
Common algorithm interview has been out! Machine learning algorithm interview - KDnuggets
This article will introduce you to jest unit test
5.5 controlleradvice notes - SSM in depth analysis and project practice
一篇文章带你了解CSS对齐方式
“颜值经济”的野望:华熙生物净利率六连降,收购案遭上交所问询
一篇文章带你了解CSS 分页实例
从海外进军中国,Rancher要执容器云市场牛耳 | 爱分析调研
数字城市响应相关国家政策大力发展数字孪生平台的建设
做外包真的很难,身为外包的我也无奈叹息。
Real time data synchronization scheme based on Flink SQL CDC
教你轻松搞懂vue-codemirror的基本用法:主要实现代码编辑、验证提示、代码格式化
Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
Nodejs crawler captures ancient books and records, a total of 16000 pages, experience summary and project sharing