前言
裝飾器 decorator 是一種函數,是 Es6 的一個語法糖,是一種與類(class)相關的語法,用來注釋或修改類和方法
以@+函數名形式展現,可以放在類和類方法的定義前面
那它在 React 中是如何使用的呢,這里以create-react-app腳手架搭建的項目為例
為什么要使用裝飾器模式?
在設計模式中講到優先使用對象而不是類繼承,動態的給對象添加一些額外的屬性或方法,相比與使用繼承,裝飾器模式更加靈活
在 React 中,高階組件是一個非常厲害的東西,它最大的特點就是能夠:重用組件邏輯.達到精簡代碼能力
前提條件
在使用這種裝飾器方式時,需要對create-react-app做一些配置,它默認是不支持裝飾器模式的,需要對項目做一些配置
在項目根目錄中終端下使用npm run eject,這條命令主要是將我們的配置項做一個反向輸出,暴露出隱藏的 webpack 配置項,這樣可以項目進行修改了的,注意它是不可逆的
方式 1-經過 eject 后在 package.json 中的 plugins 中配置
使用裝飾器,需要使用babel來進行轉換,用到的插件是@babel/plugin-proposal-decorators
當用eject將webpack一些配置彈射出來以后,會看到根目錄下的package.json文件下新增了很多文件
在babel對象處進行插件的配置,將@babel/plugin-proposal-decorators添加到plugins后
{
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{ "legacy": true }
]
]
}
}
注意
create-react-app 腳手架中已經安裝了 @babel/plugin-proposal-decorators 插件,如果是自己配置的腳手架,則先要安裝插件:`npm install @babel/plugin-proposal-decorators --save-dev
當然有一個比較便捷的寫法就是使用安裝babel-plugin-transform-decorators-legacy
{
"babel": {
"presets": [
"react-app"
],
"plugins":[
"transform-decorators-legacy"
]
}
}
注意
如果使用的是 vscode, 可以在項目根目錄下添加 jsconfig.json 文件來消除代碼警告
{
"compilerOptions": {
"experimentalDecorators": true
}
}
或者在 vscode 中的設置中tsconfig啟動Experimental Decorators就可以解決此警告
方式 2-安裝 babel 插件在 babelrc 中配置
在使用這種裝飾器方式時,需要對create-react-app做一些配置,它默認是不支持裝飾器模式的,你需要對項目做一些配置
在create-react-app根目錄中終端下使用npm run eject,這條命令主要是將我們的配置項做一個反向輸出,暴露出隱藏的 webpack 配置項,這樣可以項目進行修改了的,注意它是不可逆的
使用裝飾器模式時:需要安裝兩個依賴:
cnpm install -D babel-preset-stage-2
cnpm install -D babel-preset-react-native-stage-0
然后你需要在根目錄下創建一個.babelrc文件,對.babelrc文件做一些配置
{
"presets": ["react-native-stage-0/decorator-support"]
}
經過這么配置后,就可以使用裝飾器了的
未使用裝飾器之前
如下是componentA.js一個高階組件
import React, { Component } from 'react';
function A(WrappedComponent) {
// 函數接收一個組件為參數,並返回一個類組件,繼承自Component
return class componentA extends Component {
render() {
return (
);
}
};
}
export default A;
如下componentB.js一個組件
import React, { Component } from 'react';
import A from './componentA'; // 引入高階組件
class componentB extends Component {
render() {
return
}
}
export default A(componentB); // 直接調用A,將組件componentB作為參數傳入
如果嵌套層次很多,會發現這種代碼不優雅,很難理解,如果用裝飾器,就解決了多層嵌套的問題
使用裝飾器
在componentB.js組件中
import React, { Component } from 'react';
import A from './componentA'; // 引入高階組件
@A // 直接@+函數名就可以了的
class componentB extends Component {
render() {
return
}
}
export default componentB; // 這里直接返回componentB組件
你可以給高階組件添加靜態屬性,以及實例屬性
import React, { component } from 'react';
function Foo(params) {
params.title = 'itclanCoder';
params.prototype.decorator =
'decorator是裝飾器,即@+函數名,用來注釋或修改類方法';
}
@Foo
class ComponentA extends Component {
render() {
return (
{ComponentA.title}
{ComponentA.decorator}
);
}
}
在調用裝飾器的時候,可以往里面傳入實參,則在函數需要return一個函數,return 返回的函數參數是類的本身,下面的 Foo 函數可以接受參數,這就等於可以修改裝飾器的行為
import React, { component } from 'react';
function Foo(isAble) {
return function(target) {
target.isAble = isAble;
};
}
@Foo(false)
class ComponentA extends Component {
render() {
return
}
}
TypeScript
如果你的項目已經開始使用TypeScript,那我們只需要在tsconfig.json文件中的 experimentalDecorators 設置為 true
就可以使用 ES7 新特性裝飾器了
解決 vscode 中不支持 decorator 語法警告問題
在項目根目錄創建tsconfig.json,設置如下所示
{
"compilerOptions": {
"experimentalDecorators": true,
"allowJs": true
}
}
注意事項
⒈ 裝飾器對類的行為的改變時代碼編譯時發生的,而不是在運行時,這意味着,裝飾器能在編譯階段運行代碼,它本身就是編譯時執行的函數
⒉ 裝飾器只能用於類和類的方法,不能用於函數,因為它存在函數提升
結語
高階組件是函數,參數是組件並返回一個組件的函數,允許向一個現有的對象添加新的功能,增加靜態屬性於實例屬性,又不改變結構,屬於包裝器模式的一種
因為 Es7 中添加了 decorator 屬性,使用@函數名表示,在編寫 React 組件時,高階組件是一個非常實用的東西
或許不知不覺中,自己就已經實現了的,很久以前看過設計模式中的裝飾器模式,一直雲里霧里,不知道這個東西有什么用
直到它在 React 中高階組件還可以簡寫,這么用..
如果您有關裝飾器問題,歡迎給我留言,一起學習探討