您(可能)在React代码中最常见的错误


受媒体上阅读文章的启发,我决定写我的文章,并告诉您如何避免React应用程序中最常见的错误以及为什么需要这样做。


所有代码都是以ES6风格编写的,因此要重复进行,您需要在项目中使用Babel (还有其他人不使用它吗?)。


我试图尽可能详细地解释每个错误,因此,我的文章更侧重于仍在寻找新知识的年轻开发人员。 在我看来,尽管经验丰富的开发人员可以在本文中为自己找到一些有趣的事情。


如果您有兴趣,那就欢迎猫。


在每个段落之前的方括号中,我保留了eslint规则的链接。 您以后可以在git中找到它们并将它们添加到您的项目中。



(反应/禁止组件道具)


第一个常见错误是将“样式”和“ className”作为道具传递给组件。 避免这种情况,因为这会增加组件的复杂性。


相反,您可以使用“类名”库并向您的组件添加有趣的变体(如果使用css类):


const { hasError, hasBorder } = this.props; const componentClasses = classnames({ 'your-component-main-class': true, 'your-component-main-class_with-error': hasError, 'your-component-main-class_with-border': hasBorder, }); 


(反应/禁止道具类型)


下一个错误不是信息丰富的propTypes。 不要使用PropTypes.any,PropTypes.array和PropTypes.object。 尽可能详细地描述您的道具。 这将使您为将来留下良好的文档,并且您(或其他开发人员)将多次感谢您。


 class MyComponent extends React.Component { static propTypes = { user: PropTypes.shape({ id: PropTypes.number, name: PropTypes.string, }), policies: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.number, type: PropTypes.string, value: PropTypes.string, }), } } 


(反应/禁止外国道具类型)


让我们继续propTypes。 不要使用其他组件的propTypes:


 import SomeComponent from './SomeComponent'; SomeComponent.propTypes; 

创建一个文件,在其中您将按顺序保留全局propTypes:


 import { userShape, policiesArray } from '../common/global_prop_types'; 

这将有助于babel-plugin-transform-react-remove-prop-types从生产代码中删除propTypes,并使您的应用程序更容易一些。



(反应/设置状态为无访问状态)


以下错误非常有趣:


 class MyComponent extends React.Component { state = { counter: 1, }; incrementCounter = () => this.setState({ counter: this.state.counter + 1 }); massIncrement = () => { // this code will lead to not what you expect this.incrementCounter(); this.incrementCounter(); } } 

因为setState是状态的异步状态函数,所以两种情况都是相同的。
this.state.counter将为1,我们将获得:


 incrementCounter = () => this.setState({ counter: 1 + 1 }); incrementCounter = () => this.setState({ counter: 1 + 1 }); 

为了避免这种情况,可以使用setState回调,该回调将状态状态作为参数接收:


 incrementCounter = () => this.setState((prevState) => ({ counter: prevState.counter + 1 })); 


(反应/ no-array-index-key)


此错误也很常见,因此请仔细阅读并在以后避免它:


 users.map((user, index) => ( <UserComponent {...user} key={index} /> )); 

React使用prop键作为到DOM元素的链接,这有助于它快速找到并呈现必要的组件(当然,所有事情都比较复杂,但我故意对此进行了简化)。
如果在阵列中间添加新用户,会发生什么情况? 添加新组件后,React将被强制重新渲染所有UserComponent,因为索引将针对大量组件进行更改。 请改用唯一键。 一个非常简单的方法是从数据库获取ID:


 users.map((user) => ( <UserComponent {...user} key={user.id} /> )); 


(反应/没有更新设置状态),(反应/没有更新设置状态)


这个错误在我的实践中也很常见。 如果尝试在componentDidUpdate方法中更新状态,则会得到无限的重新渲染循环。 当组件更改状态或道具时,React开始检查是否重新渲染。 如果在组件安装到DOM中或已经更新后更改状态,则将一次又一次地运行检查...
在componentDidMount中更新状态时,您可以再次调用该组件一次,因为在将组件安装在DOM中之后,该函数将被调用一次。
如果在安装组件后需要更新数据,建议使用类变量:


 class MyComponent extends React.Component { componentDidMount() { this.veryImportantDataThatCanBeStoredOnlyAfterMount = 'I'll be back!'; } veryImportantDataThatCanBeStoredOnlyAfterMount = void 0; render() { return <div /> } } 


(反应/无直接突变状态)


状态突变是一个很大的错误。 不受控制的状态突变将导致无法检测的错误,并因此导致大问题。 我个人的观点是使用immutable-js作为添加不可变结构的库。 您可以将它们与Redux / MobX /任何状态管理库一起使用。 您还可以使用lodash中的deepClone来克隆状态,然后对克隆进行突变,或者使用新的JS功能-解构:


 updateStateWrong = () => this.state.imRambo = true; updateStateRight = () => { const clonedState = cloneDeep(this.state); clonedState.imAGoodMan = true; this.setState(clonedState); } updateWithImmutabelJS = () => { const newState = this.state.data.set('iUseImmutableStructure', true); this.setState(data: newState); } updateWithDestructuring = () => this.setState({ ...this.state, iUseDestructuring: true }); 


(反应/首选无状态功能)


该规则比错误描述了代码和应用程​​序的更多改进,但是我仍然建议您遵循此规则。 如果您的组件不使用状态,请使其成为无状态组件(我更喜欢术语“纯组件”):


 class MyComponentWithoutState extends React.Component { render() { return <div>I like to write a lot of unneeded code</div> } } const MyPureComponent = (props) => <div>Less code === less support</div> 


(反应/道具类型)


如果您的组件收到道具,请务必添加道具类型检查(propTypes)。 可以将其视为记录您的代码。 您会不止一次对自己说“谢谢”(也许对我说:))。 PropTypes将帮助您了解和理解组件可以呈现的内容以及呈现所需的内容。


 MyPureComponent.propTypes = { id: PropTypes.number.isRequired, // And I know that without id component will not render at all, and this is good. } 


(反应/ jsx-no-bind)


我在代码中多次看到的一个非常常见的大错误。 不要在Jsx中使用Bind and Arrow函数。 没关系 更多
地狱中最热的地方正等待着在事件处理程序中用JSX写.bind(this)的人。
每次呈现组件时,都会重新创建函数,这会大大降低应用程序的速度(这是由于垃圾收集器将被迫更频繁地运行)。 代替.bind(this),您可以通过某种方式使用Arrow函数:


 class RightWayToCallFunctionsInRender extends React.Component { handleDivClick = (event) => event; render() { return <div onClick={this.handleDivClick} /> } } const handleDivClick = (event) => event; const AndInPureComponent = () => { return <div onClick={handleDivClick} /> } 


(反应/ jsx-no-target-blank)


安全漏洞。 人们仍然会犯这个错误,这对我来说似乎很奇怪。 2017年有很多人为此主题写了很多文章。
如果使用target ='_ blank'属性创建链接,请确保在其中添加rel ='noreferrer noopener'。 很简单:


 <a href="https://example.com" target="_blank" rel="noreferrer noopener" /> 

谢谢啦


作为本文的一部分,我仅想告诉您。 如果您,我的读者,对我在本文中描述的问题,留下您的反馈或评论并分享您的意见,我将非常感谢。 另外,您可以告诉我我和您在代码中的错误以及您认为需要告知的所有内容。 再次谢谢你!

Source: https://habr.com/ru/post/zh-CN416511/


All Articles