[干货]介绍4个开发React应用的实用技巧
BackgroundHooks自上线以来就大受欢迎。它改变了我们编写React代码的方式,帮助我们编写更简洁的代码。今天的文章不是关于Hooks的。除了Hooks,还有很多实用的技巧可以帮助我们写出简洁明了的代码。今天整理了几个我用过的技巧,其中一些我在公司的项目中也实践过,现整理出来分享给大家,希望对大家有所启发。文本1.使用字符串定义React元素举个简单的例子://我们可以将字符串'div'赋给一个变量,例如:importReactfrom'react'constMyComponent='div'functionApp(){return(<>我在一个{'
'}元素里面>)}React会在里面调用React.createElement,使用这个String来生成这个元素.此外,还可以显式定义组件来确定渲染的内容,例如://定义一个MyComponentfunctionMyComponent({component:Component='div',name,age,email}){return(你好{name}
<>你{age}岁
你的邮箱是{email}>)}适用方法:functionApp(){return(<>>)}这样也可以通过在自定义组件中,例如:functionDashboard({children}){return({children}
)}functionApp(){return(<>
>)}如果遇到类似的元素或组件,可以使用这种自定义方式被抽象出来,简化了你的代码。举一个现实的例子:比如我们现在需要对商品进行包装,可以单独打印也可以批量打印。我们可以为共同点编写自定义组件:=>{constpackRes=usePack(props)return()}PackEditor=withTranslate(PackEditor)PackEditor.check=checkexportdefaultPackEditor可以在不同的业务模块中灵活使用,非常方便.2、定义错误边界在Javascript中,我们都是使用try/catch来捕捉可能出现的异常,在catch中处理错误。例如:functiongetFromLocalStorage(key,value){try{constdata=window.localStorage.get(key)returnJSON.parse(data)}catch(error){console.error}}这样,即使报错发生时,我们的应用程序不会崩溃到白屏。React归根结底也是Javascript,本质上没有区别,所以用同样的方式使用try/catch是没有问题的。但是由于React的实现机制,组件内部发生Javascript错误会破坏内部状态,render会产生错误:https://github.com/facebook/react/issues/4026基于以上原因,React团队介绍了ErrorBoundaries:https://reactjs.org/docs/erro...错误边界,其实就是React组件,你可以使用一个组件来处理它捕捉到的任何错误信息。当组件树折叠时,您还可以显示自定义UI作为后备。看React官方提供的例子:https://reactjs.org/docs/erro...classErrorBoundaryextendsReact.Component{constructor(props){super(props)this.state={hasError:false}}staticgetDerivedStateFromError(error){//更新状态,以便下一次渲染将显示后备UI。return{hasError:true}}componentDidCatch(error,errorInfo){//你也可以将错误记录到错误报告服务logErrorToMyService(error,errorInfo)}render(){if(this.state.hasError){//你可以呈现任何自定义后备UI返回出现问题。
}returnthis.props.children}}用法:DanAbramov的现场演示:https://codepen.io/gaearon/pe...3.高层组件一般来说,所谓高层组件就是,你丢一个组件进去,添加一些属性或者操作,然后丢出去。一般来说,你可以将一些通用的组件抽象成一个高层组件,然后在不同的模块中复用。比如在我们的系统中,有一类按钮需要加边框,很多地方都会用到。我们抽象它:importReactfrom'react'//HigherordercomponentconstwithBorder=(Component,customStyle)=>{classWithBorderextendsReact.Component{render(){conststyle={border:this.props.customStyle?this.props.customStyle.border:'3pxsolidteal'}return}}returnWithBorder}functionMyComponent({style,...rest}){return(这是我的组件,我期待一些
)}exportdefaultwithBorder(MyComponent,{border:'4pxsolidteal'})用withBorder装饰的MyComponent组件具有统一边框的功能。如果后面要修改的话,可以在这个中间层统一处理,非常方便。在我的项目中,也使用了一些高级组件。举一个具体的例子:PackEditor=withTranslate(PackEditor)我们的PackEditor是一个增强的组件。增加了哪些功能?顾名思义,withTranslate增加了一个翻译功能,下面给大家介绍一下这个组件是如何实现的:store}from'@redux/store'import{Intl}from'./Locale'constwithTranslate=BaseComponent=>(props)=>{//避免在重新渲染时创建新组件constIntlComponent=React.useMemo(()=>injectIntl??(({intl,...others})=>(
{//注入翻译方法if(!id){return''}returnintl.formatMessage(typeofid==='string'?{id}:id,values)}}{...others}/>)),[])IntlComponent.displayName=`withTranslate(${BaseComponent.displayName||'BaseComponent'})`返回()}exportdefaultwithTranslate非常有用:constEditor=withTranslate(({//...translate,})=>{//...return(<>{translate('xxx')}}>)})很方便4.RenderpropsRrenderprop是指React组件之间的共享代码,使用一个值为函数的prop简单的技术HOC的实现,类似于HOC,是组件间的逻辑复用问题。更具体地说,Renderprop是一个函数,它告诉组件要渲染什么。让我们看一个简单的例子:以下组件跟踪鼠标在Web应用程序中的位置:classMouseextendsReact.Component{state={x:0,y:0};handleMouseMove=(event)=>{this.setState({x:event.clientX,y:event.clientY});}render(){return(当前鼠标位置为({this.state.x},{this.state.y})
);}}classMouseTrackerextendsReact.Component{render(){return(<>
移动鼠标!
>);}}当光标在屏幕上移动时,组件显示其(x,y)坐标。现在的问题是:我们如何在另一个组件中重用这个行为?换句话说,如果另一个组件需要知道鼠标位置,我们是否可以封装此行为以便我们可以轻松地与其他组件共享??假设产品需要这样的功能:在屏幕上呈现一张猫在屏幕上追逐鼠标的图片。我们可以使用
);}}这个需求很简单,直接修改Mouse组件即可:classMouseextendsReact.Component{state={x:0,y:0};handleMouseMove=(event)=>{this.setState({x:event.clientX,y:event.clientY});}render(){return(
);}}巴适~简单粗暴,一分钟完成任务。但是,如果你想在下一个产品中添加一只狗怎么办?上面的例子虽然可以实现猫追老鼠的要求,但是还没有达到真正将行为封装为可重用的目的。当我们想要不同用例的鼠标位置时,我们必须创建一个新组件来呈现特定于该用例的内容。这就是renderprop的用武之地:我们可以提供一个带有函数prop的