4個開發React應用的實用技巧
【相關專題推薦:react面試題(2020)】
背景
Hooks 自推出以來就很火, 它改變了我們編寫React 程式碼的方式, 有助於我們寫更簡潔的程式碼。
今天這邊文章不是說Hooks的,Hooks之外, 還有很多實用的技巧可以幫助我們寫出簡潔清晰
的程式碼。
今天我就整理了幾個使用的技巧,其中有些也是我在公司專案中實踐的
,現在整理出來分享給大家, 希望對大家有所啟發
。
正文
#1. 使用字串來定義一個React元素
#舉個簡單的例子:
// 我们可以通过把一个字符串'p' 赋值给一个变量, 就像: import React from 'react' const MyComponent = 'p' function App() { return ( <mycomponent> <h3 id="I-am-inside-a">I am inside a {'</h3> <p></p>'} element </mycomponent> > ) }
React 內部會呼叫React.createElement
, 使用這個字串來產生這個元素。
另外, 你也可以明確的定義component
來決定渲染的內容, 例如:
// 定义一个MyComponent function MyComponent({ component: Component = 'p', name, age, email }) { return ( <component> <h1 id="Hi-name">Hi {name} </h1> <h6 id="You-are-age-years-old">You are {age} years old</h6> <small>Your email is {email}</small> > </component> ) }
適用方式:
function App() { return ( <mycomponent> > ) }</mycomponent>
這種方式, 你也可以傳入一個自訂的元件, 例如:
function Dashboard({ children }) { return ({children}
) } function App() { return ( <mycomponent> > ) }</mycomponent>
如果你遇到處理一類相似的
元素或元件,可以透過這種自訂的方式抽像出來,簡化你的程式碼。
舉個現實的例子:
例如我們現在要做一個貨物打包的需求, 可以單一打, 也可以批量打, 針對共同點可以寫自訂元件:
import React from 'react' import withTranslate from '@components/withTranslate' import PackComponent from './PackComponent' import usePack, { check } from './usePack' let PackEditor = (props) => { const packRes = usePack(props) return ( <packcomponent></packcomponent> ) } PackEditor = withTranslate(PackEditor) PackEditor.check = check export default PackEditor
這樣在不同的業務模組中, 就可以靈活的使用了, 非常方便。
2. 定義錯誤邊界
在Javascript裡,我們都是使用try/catch
來捕捉可能發生的異常,在catch
中處理錯誤。例如:
function getFromLocalStorage(key, value) { try { const data = window.localStorage.get(key) return JSON.parse(data) } catch (error) { console.error } }
這樣, 即使發生了錯誤, 我們的應用也不至於崩潰白螢幕。
React 歸根究底也是Javascript,本質上沒什麼不同, 所以同樣的使用try/catch
也沒問題。
然而, 由於React 實作機制的原因, 發生在元件內部的Javascript 錯誤會破壞內部狀態, render會產生錯誤:
https://github.com/facebook/react/ issues/4026
基於以上原因,React 團隊引入了Error Boundaries
:
https://reactjs.org/docs /error-boundaries.html
Error boundaries
, 其實就是React元件, 你可以用找個元件來處理它捕捉到的任何錯誤訊息。
當元件樹崩潰的時候,也可以顯示你自訂的UI,作為回退。
看React 官方提供的範例:
https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries
class ErrorBoundary extends React.Component { constructor(props) { super(props) this.state = { hasError: false } } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true } } componentDidCatch(error, errorInfo) { // You can also log the error to an error reporting service logErrorToMyService(error, errorInfo) } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1 id="Something-went-wrong">Something went wrong.</h1> } return this.props.children } }
使用方式:
<errorboundary> <mywidget></mywidget> </errorboundary>
Live Demo By Dan Abramov:
https://codepen.io/gaearon/pen/wqvxGa?editors=0010
3.高階元件
通俗點講, 所謂高階元件就是, 你丟一個元件進去, 增加一些屬性或操作, 再丟出來。
一般來說, 你可以把一些具備共同點的
元件抽象化成一個高階元件
, 然後再不同的模組中重複使用
。
例如, 我們的系統中, 有一類按鈕要加個border
, 很多地方都要用到, 我們把它抽像出來:
import React from 'react' // Higher order component const withBorder = (Component, customStyle) => { class WithBorder extends React.Component { render() { const style = { border: this.props.customStyle ? this.props.customStyle.border : '3px solid teal' } return <component></component> } } return WithBorder } function MyComponent({ style, ...rest }) { return ( <p> </p><h2> This is my component and I am expecting some styles. </h2> ) } export default withBorder(MyComponent, { border: '4px solid teal' })
經過withBorder裝飾的MyComponent元件, 就具備了統一border這項功能, 後面如果如果要做修改, 就可以在這個中間層
統一處理, 非常方便。
在我的專案裡, 也用了一些高階元件, 舉個具體的例子:
PackEditor = withTranslate(PackEditor)
我們的這個PackEditor
就是一個增強過的元件,增加了什麼功能呢?
如同名字表達的, withTranslate
, 增加了一個翻譯功能, 下面也給大家看看這個元件是怎麼實現的:
import React from 'react' import { Provider } from 'react-redux' import { injectIntl } from 'react-intl' import { store } from '@redux/store' import { Intl } from './Locale' const withTranslate = BaseComponent => (props) => { // avoid create a new component on re-render const IntlComponent = React.useMemo(() => injectIntl( ({ intl, ...others }) => ( <basecomponent> { // 注入翻译方法 if (!id) { return '' } return intl.formatMessage( typeof id === 'string' ? { id } : id, values ) }} {...others} /> ) ), []) IntlComponent.displayName = `withTranslate(${BaseComponent.displayName || 'BaseComponent'})` return ( <provider> <intl> <intlcomponent></intlcomponent> </intl> </provider> ) } export default withTranslate</basecomponent>
用法很靈過:
const Editor = withTranslate(({ // ... translate, }) => { // ... return ( {translate('xxx')}} > ) })
十分的方便。
4. Render props
Rrender prop 是指一種在React 元件之間
使用一個值為函數的prop 共享代碼
的簡單技術, 和HOC 類似,都是組件間的邏輯復用問題
。
更具體地說,Render prop 是一個用來告知元件需要渲染什麼內容
的函數。
下面看一下簡單的例子:
以下元件追蹤Web 應用程式中的滑鼠位置:
class Mouse extends React.Component { state = { x: 0, y: 0 }; handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ( <p> </p><p>The current mouse position is ({this.state.x}, {this.state.y})</p> ); } } class MouseTracker extends React.Component { render() { return ( <h1 id="移动鼠标">移动鼠标!</h1> <mouse></mouse> > ); } }
當遊標在螢幕上移動時,元件顯示其(x ,y)座標。
現在的問題是:
我們如何在另一個元件中重複使用這個行為?
换个说法,若另一个组件需要知道鼠标位置,我们能否封装这一行为,以便轻松地与其他组件共享它 ??
假设产品想要这样一个功能: 在屏幕上呈现一张在屏幕上追逐鼠标的猫的图片。
我们或许会使用 这个需求如此简单,你可能就直接修改Mouse组件了: 巴适~ 简单粗暴, 一分钟完成任务。 可是,如果下次产品 以上的例子,虽然可以完成了猫追鼠标的需求,还没有达到以 当我们想要鼠标位置用于不同的用例时,我们必须创建一个新的组件,专门为该用例呈现一些东西. 这也是 render prop 的来历: 我们可以提供一个带有函数 prop 的 修改一下上面的代码:
{this.props.render(this.state)}
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/static/imghw/default1.png" data-src="/cat.jpg" class="lazy" alt="4個開發React應用的實用技巧" >
);
}
}
class Mouse extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<p>
<cat></cat>
</p>
);
}
}
再要想加条狗呢
?可复用的方式
真正封装行为的目标。<mouse></mouse>
组件,它能够动态决定
什么需要渲染的,而不是将 硬编码
到 class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/static/imghw/default1.png" data-src="/cat.jpg" class="lazy" alt="4個開發React應用的實用技巧" >
);
}
}
class Mouse extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
移动鼠标!
提供了一个render 方法,让动态决定什么需要渲染。
事实上,render prop 是因为模式才被称为 render prop ,不一定要用名为 render 的 prop 来使用这种模式。
任何被用于告知组件需要渲染什么内容的函数 prop, 在技术上都可以被称为 "render prop".
另外,关于 render prop 一个有趣的事情是你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。
例如,如果你更喜欢使用 withMouse HOC 而不是
function withMouse(Component) { return class extends React.Component { render() { return ( <mouse> ( <component></component> )}/> ); } } }</mouse>
也是非常的简洁清晰。
有一点需要注意的是, 如果你在定义的render函数里创建函数, 使用 render prop 会抵消
使用 React.PureComponent 带来的优势。
因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值
。
class Mouse extends React.PureComponent { // 与上面相同的代码...... } class MouseTracker extends React.Component { render() { return ( <mouse> ( // 这是不好的! 每个渲染的 `render` prop的值将会是不同的。 <cat></cat> )}/> > ); } }</mouse>
在这样例子中,每次
为了绕过这一问题
,有时你可以定义一个 prop 作为实例方法
,类似这样:
class MouseTracker extends React.Component { renderTheCat(mouse) { return <cat></cat>; } render() { return ( <p> </p><h1 id="Move-the-mouse-around">Move the mouse around!</h1> <mouse></mouse> ); } }
5.组件性能
性能优化是永恒的主题, 这里不一一细说, 提供积分资源供你参考:
- React.memo https://reactjs.org/docs/reac...
- React.useMemo https://flaviocopes.com/react...
- React.useCallback https://reactjs.org/docs/hook...
- React.PureComponent https://reactjs.org/docs/reac...
- Optimizing performance https://reactjs.org/docs/opti...
总结
以上几点都是我们经常要使用的技巧, 简单实用, 分享给大家, 希望能给大家带来一些帮助或启发,谢谢。
推荐阅读:React在线手册
以上是4個開發React應用的實用技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

JS-Torch簡介JS-Torch是一種深度學習JavaScript函式庫,其語法與PyTorch非常相似。它包含一個功能齊全的張量物件(可與追蹤梯度),深度學習層和函數,以及一個自動微分引擎。 JS-Torch適用於在JavaScript中進行深度學習研究,並提供了許多方便的工具和函數來加速深度學習開發。圖片PyTorch是一個開源的深度學習框架,由Meta的研究團隊開發和維護。它提供了豐富的工具和函式庫,用於建立和訓練神經網路模型。 PyTorch的設計理念是簡單和靈活,易於使用,它的動態計算圖特性使

Go和Node.js在類型化(強/弱)、並發(goroutine/事件循環)、垃圾收集(自動/手動)上有差異。 Go具備高吞吐量、低延遲,適用於高負載後端;Node.js擅長異步I/O,適合高並發、短請求。兩者的實戰案例包括Kubernetes(Go)、資料庫連線(Node.js)、網路應用程式(Go/Node.js)。最終選擇取決於應用程式需求、團隊技能和個人偏好。

JavaScript和WebSocket:打造高效率的即時搜尋引擎引言:隨著網路的發展,使用者對即時搜尋引擎的要求也越來越高。傳統的搜尋引擎在進行搜尋時,使用者需要點擊搜尋按鈕後才能得到結果,這種方式無法滿足使用者對於即時搜尋結果的需求。因此,採用JavaScript和WebSocket技術來實現即時搜尋引擎成為了一個熱門的話題。本文將詳細介紹使用JavaScri

Vue.js主要用於前端開發。 1)它是一個輕量級且靈活的JavaScript框架,專注於構建用戶界面和單頁面應用。 2)Vue.js的核心是其響應式數據系統,數據變化時視圖自動更新。 3)它支持組件化開發,UI可拆分為獨立、可複用的組件。
