項目升級到 React19 難度如何?生態(tài)初探:利用 React-markdown 實現(xiàn)代碼高亮
經(jīng)過前面幾個實踐案例的學(xué)習(xí),我們都已經(jīng)知道,React19 有非常吸引開發(fā)者的特性值得我們?nèi)ド墶5桥c此同時,我們也感受到了某些改動確實挺大的。因此在交流群里,大家會有一個比較明顯的擔(dān)憂,這種比較大的版本更新,是否會導(dǎo)致升級困難?
其實在官方文檔中的升級指引中,有明確提到這個問題,開發(fā)團隊預(yù)計這些重大更改不會影響到大多數(shù)程序。并且我們看到,react 刪除的功能中,大多數(shù)都是幾年前都已經(jīng)標(biāo)記棄用不建議大家使用的內(nèi)容。
例如,class 語法中,曾經(jīng)支持了字符串引用 ref。
// before
class MyComponent extends React.Component {
componentDidMount() {
this.refs.input.focus();
}
render() {
return <input ref='input' />;
}
}
這種使用方式因為存在多個缺點,在 2018 年 3 月(V16.3.0)中被標(biāo)記為不推薦使用,直到現(xiàn)在才明確要刪除代碼。調(diào)整之后,開發(fā)者需要遷移到 ref 回調(diào)函數(shù)的使用。這個也并非新功能,而是一直都支持的寫法,因此開發(fā)者有充裕的時間來解決這個問題。
// after
class MyComponent extends React.Component {
componentDidMount() {
this.input.focus();
}
render() {
return <input ref={input => this.input = input} />;
}
}
又例如,React19 決定要移出 ReactDOM.findDOMNode,這個 API 曾經(jīng)在三方庫中被大量使用,但是他已經(jīng)在 2018 年 10 月被標(biāo)記為廢棄。由于他是一個性能較差,又容易受到重構(gòu)影響,因此風(fēng)險會比較大。
// Before
import {findDOMNode} from 'react-dom';
function AutoselectingInput() {
useEffect(() => {
const input = findDOMNode(this);
input.select()
}, []);
return <input defaultValue="Hello" />;
}
在 React18 的版本中,提供了新的方案來替換該用法。
// After
function AutoselectingInput() {
const ref = useRef(null);
useEffect(() => {
ref.current.select();
}, []);
return <input ref={ref} defaultValue="Hello" />
}
當(dāng)然,其他的變化還有很多,我們就不一一列舉,許多破壞性變更早在 React18 中就已經(jīng)存在,因此對于長期維護的三方庫而言,React19 的升級壓力非常小。并且為了簡化升級過程,React 發(fā)布了一個過渡版本 React 18.3,該版本功能與 React 18.2 相同,但是增加了對已棄用 API 代碼的刪除,并且調(diào)整了相關(guān)的警告。
目前,該過渡版本已經(jīng)發(fā)布了剛好半個月,但已經(jīng)被開發(fā)者大規(guī)模使用了。如下圖所示,這個下載量,已經(jīng)大概相當(dāng)于 Vue 的整體使用水平了,所以整個行業(yè)對于 React19 的升級響應(yīng)非常積極。
與此同時,我們還可以利用 react 團隊之前發(fā)布的一個工具用于在代碼中自動替換棄用的寫法,他就是 react-codemod。
因此總體來說,我們應(yīng)該可以輕松的在 react19 中應(yīng)用大多數(shù)目前仍然保持維護的三方工具庫。為了驗證我的猜想,我在 React19 項目中引入了許多我正在使用的三方工具庫來嘗試。這里就以 react-markdown 為例,跟大家分享一下在新項目中的運用情況。
react-markdown 是 react 生態(tài)中,一個非常好用 的 md 文件解析工具。依據(jù)這個工具,我們可以輕松創(chuàng)建一個 md 編輯器。
如果你要設(shè)計一個個人博客,并且需要展示技術(shù)類文章,這個工具可以很好幫助到你。我們這里以展示一個高亮代碼塊為目標(biāo),分享引入過程。
首先我們在項目中,引入 react-markdown。
npm i react-markdown
有了這個之后,我們就可以在項目中解析一些簡單的 md 格式。
例如,我們可以解析如下格式。
const input = '# This is a header\n\nAnd this is a paragraph'
在頁面中引入 react-markdown。
import Markdown from 'react-markdown'
然后直接在 JSX 中使用即可。
<Markdown>{input}</Markdown>
渲染結(jié)果如下:
完了之后,有一些比較復(fù)雜的格式,react-markdown 可以引入不同的插件來支持。
例如,react-gfm,可以幫助我們解析列表等格式,如下所示:
const text2 = `A paragraph with *emphasis* and **strong importance**.
> A block quote with ~strikethrough~ and a URL: https://reactjs.org.
* Lists
* [ ] todo
* [x] done
A table:
| a | b |
| - | - |
`
安裝插件。
npm i remark-gfm
然后直接在組件中使用即可。
import remarkGfm from 'remark-gfm'
// jsx
<Markdown remarkPlugins={[remarkGfm]}>
{text2}
</Markdown>
渲染結(jié)果如下。由于我沒有引入 css,因此樣式比較原始。
我們可以通過查看 html 標(biāo)簽來查看渲染結(jié)果。驗證之后發(fā)現(xiàn)已經(jīng)渲染成功。
當(dāng)然,如果我們要渲染代碼快,也需要引入特定的插件,我這里使用了 rehype-highlight。
npm i rehype-highlight
安裝好之后,我們可以專門在 .md 文件中編寫好 md 內(nèi)容,在 vite 項目中,可以直接通過如下方式引入 .md 文件。
import code from './code.md?raw'
然后在頁面組件中使用。
import rehypeHighlight from 'rehype-highlight'
// jsx
<Markdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeHighlight]}
>{code}</Markdown>
此時,我們觀察頁面,發(fā)現(xiàn)標(biāo)簽已經(jīng)渲染好了。
但是此時我們還沒有樣式文件。當(dāng)然,我們可以直接自己根據(jù)對應(yīng)元素中的 class 名來寫樣式。
由于設(shè)計能力有限,我一般引用別人已經(jīng)設(shè)計好的樣式文件。
如下這個網(wǎng)站收集了大量的高亮風(fēng)格,我們直接復(fù)制代碼使用即可。
https://highlightjs.tiddlyhost.com
我選擇了一個,把他單獨寫在一個 css 文件中,并引入對應(yīng)的組件。渲染結(jié)果如下:
搞定!
總結(jié)
在我嘗試了幾個三方庫之后,總體感受就是基本上都能正常在 React19 項目中使用,即使這些三方庫還沒有升級到 react19。當(dāng)然我也把我某一個 React18 的項目升級到 React19,小幅度更改之后,也成功升級了。
因此我預(yù)計我們有希望在 react19 正式版本發(fā)布之后不久把項目正式升級。
但是,一個不太好的消息是,antd 由于使用了一些很早版本就棄用的方法,例如 findDOMNode,還有一些 React19 會棄用的 api, 例如 forwardRef,導(dǎo)致了 antd 一運行就各種報錯。許多組件無法正常使用。這種就只能等 antd 適配進度了,他們應(yīng)該會很快更新。