自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

能把隊(duì)友氣死的八種代碼(React版)

開(kāi)發(fā) 前端
作為大型項(xiàng)目,很容易需要依賴別的模板掛載到window對(duì)象的內(nèi)容,讀取的時(shí)候需要考慮到是否有可能拿不到window對(duì)象上的內(nèi)容,從而導(dǎo)致js報(bào)錯(cuò)?

前幾天在前端技術(shù)群里聊起Code Review的事,大伙兒似乎都憋了一肚子氣:

圖片圖片

圖片

我覺(jué)得這份難言之隱應(yīng)該要讓更多人看到,就跟Henry約了個(gè)稿:

圖片圖片

于是Henry趕在周末,一邊帶娃,一邊給我抹眼淚整理(脫敏)出了這篇小小的屎山合集,供大家品鑒。

以下是正文。

1. 直接操作DOM

const a = document.querySelector('.a');

const scrollListener = throttle(() => {
  const currentY = window.scrollY;

  if (currentY > 100) {
    a.classList.add('show');
  } else {
    a.classList.remove('show');
  }
}, 300);

window.addEventListener('scroll', scrollListener);
return () => {
  window.removeEventListener('scroll', scrollListener);
};

上面的代碼在監(jiān)聽(tīng)scroll方法的回調(diào)函數(shù)中,直接上手修改DOM的類名。眾所周知,React屬于響應(yīng)式編程,大部份情況都不需要直接操作DOM,具體原因參考官方文檔(https://react.dev/learn/manipulating-the-dom-with-refs)。

優(yōu)化方法也很簡(jiǎn)單,充分發(fā)揮響應(yīng)式編程的優(yōu)點(diǎn),用變量代替即可:

const [refreshStatus, setRefreshStatus] = useState('');

const scrollListener = throttle(() => {
  if (tab.getBoundingClientRect().top < topH) {
    setRefreshStatus('show');
  } else {
    setRefreshStatus('');
  }
}, 300);

return <div className={['page_refresh', refreshStatus].join(' ')}/>;

2. useEffect不指定依賴

依賴參數(shù)缺失。

useEffect(() => {
    console.log('no deps=====')
    // code...
});

這樣的話,每次頁(yè)面有重渲染,該useEffect都會(huì)執(zhí)行,帶來(lái)嚴(yán)重的性能問(wèn)題。

例如我們項(xiàng)目中,這個(gè)useEffect內(nèi)部執(zhí)行的是第一點(diǎn)中的內(nèi)容,即每次都會(huì)綁定一個(gè)scroll事件的回調(diào),而且頁(yè)面中有實(shí)時(shí)輪詢接口每隔5s刷新一次列表,用戶在該頁(yè)面稍加停留,就會(huì)有卡頓問(wèn)題出現(xiàn)。

解決方案很簡(jiǎn)單,根據(jù)useEffect的回調(diào)函數(shù)內(nèi)容可知,如果需要在第一次渲染之后掛載一個(gè)scroll的回調(diào)函數(shù),那么就給useEffect第二個(gè)參數(shù)傳入空數(shù)組即可,參考官方文檔(https://react.dev/reference/react/useEffect#useeffect)。

useEffect(() => {
    // code...
}, []);

3. 硬編碼

硬編碼,即一些數(shù)據(jù)信息或配置信息直接寫死在邏輯代碼中,例如

圖片

這兩行代碼本意是從url上拿到指定的參數(shù)的值,如果沒(méi)有,會(huì)用一個(gè)固定的配置做兜底。

乍一看代碼邏輯很清晰,但再想深一層,兜底值具體的含義是什么?為什么要用這兩個(gè)值來(lái)兜底?寫這行代碼的同學(xué)可能很快可以解答,但是一段時(shí)間之后,寫代碼的人和提需求的人都找不到了呢?

這個(gè)示例代碼還比較簡(jiǎn)單,拿對(duì)應(yīng)的值去后臺(tái)可以找到對(duì)應(yīng)的含義,如果是寫死的是枚舉值,而且還沒(méi)有類型定義,那代碼就很難維護(hù)了。

圖片圖片

解決此類問(wèn)題,要么將這些內(nèi)容配置化,即寫到一個(gè)config文件中,使用清晰的語(yǔ)義化命名變量;要么,至少在硬編碼的地方寫上注釋,交代清楚這里需要硬編碼的前因后果。

沐灑:

關(guān)于硬編碼問(wèn)題,我在之前的一篇關(guān)于“配置管理”的文章里有詳細(xì)闡述和應(yīng)對(duì)方案,感興趣的朋友可以看看《小白也能做出滿分前端工程:01 配置管理》

4. 放任文件長(zhǎng)度,只著眼于當(dāng)下的需求

很多同學(xué)做需求、寫代碼都比較少?gòu)娜挚紤],只關(guān)注到當(dāng)前需求如何完成。從“戰(zhàn)術(shù)”上來(lái)說(shuō)沒(méi)有問(wèn)題,快速完成產(chǎn)品的需求、快速迭代產(chǎn)品也是大家希望看到的。

可一旦只關(guān)注“戰(zhàn)術(shù)實(shí)現(xiàn)”而忽略“戰(zhàn)略設(shè)計(jì)”,除非做的產(chǎn)品是月拋型的,否則一定會(huì)遇到舊邏輯難以修改的情況。

如果再加上一個(gè)文件被多達(dá)10余人修改過(guò)的情況,那么每改一行代碼都會(huì)是一場(chǎng)災(zāi)難,例如最近接手的一個(gè)頁(yè)面:

圖片圖片

單文件高達(dá)1600多行!哪怕去除300多行的注釋,和300多行的模板,剩下的邏輯代碼也有1000行左右,這種代碼可讀性就極其糟糕,必須進(jìn)行拆分。

而很常見(jiàn)的是,由于每一任經(jīng)手人都疏于考慮全局,導(dǎo)致大量代碼毫無(wú)模塊化可言,甚至出現(xiàn)多個(gè)useEffect的依賴是完全相同的:

圖片圖片

這里明顯還有另一個(gè)問(wèn)題:濫用hooks。

從行號(hào)可以看出來(lái)確實(shí)是相同的依賴寫了多個(gè)useEffect,很明顯是多個(gè)同學(xué)各寫各的的需求引入的這些hooks。

這代碼跑肯定是能跑的,但是很可能會(huì)出現(xiàn)多個(gè)hooks中修改同一個(gè)變量,導(dǎo)致其他地方在使用的時(shí)候需要搞一些很tricky的操作來(lái)修Bug。

5.變量無(wú)初始值

在typescript的加持下,對(duì)變量的類型定義可以說(shuō)是日益嚴(yán)格了??墒窃谝恍┳兞康念愋投x比較復(fù)雜的情況下,可能一個(gè)變量的字段很多、層級(jí)很復(fù)雜,此時(shí)有些同學(xué)就可能想偷個(gè)懶了,例如:

const [variable, setVariable] = useState<ComplicatedType>();

// some code...
const queryData = function() {
    // some logic
    setVariable({ show: true });
};

useEffect(() => {
    queryData();
}, []);

return variable.show ? <Component /> : null;

這里的問(wèn)題很明顯,如果queryData耗時(shí)比較長(zhǎng),在第一次渲染的時(shí)候,最后一行的variable.show就會(huì)報(bào)錯(cuò)了,因?yàn)関ariable的初始值是undefined。所以聲明變量時(shí),一定要根據(jù)變量的類型設(shè)置好有效默認(rèn)值。

6. 三元選擇符嵌套使用

網(wǎng)上很多人會(huì)推薦說(shuō)用三元選擇符代替簡(jiǎn)單的if-else,但幾乎沒(méi)有見(jiàn)過(guò)有人提到嵌套使用三元選擇符的事情,如果看到如下代碼,不知道各位讀者會(huì)作何感想?

{condition1 === 1
    ? "數(shù)據(jù)加載中"
    : condition2
    ? "沒(méi)有更多了"
    : condition3
    ? "當(dāng)前沒(méi)有可用房間"
    : "數(shù)據(jù)加載中"}

真的很難理解,明明只是一個(gè)簡(jiǎn)單的提示語(yǔ)句的判斷,卻需要拿出分析性能的精力去理解,多少有點(diǎn)得不償失了。

這還只是一種比較簡(jiǎn)單的三元選擇符的嵌套,因?yàn)楫?dāng)各個(gè)條件分支都為true時(shí),就直接返回了,沒(méi)有做更多的判斷,如果再多做一層,都會(huì)直接把人的cpu的干爆炸了。 

替代方案: 

  1. 直接用if-else,可讀性更高,以后如果要加邏輯也很方便。
  2. Early Return,也叫衛(wèi)語(yǔ)句,這種寫法能有效簡(jiǎn)化邏輯,增加可讀性。
if (condition1 === 1) return "數(shù)據(jù)加載中";
if (condition2) return "沒(méi)有更多了";
if (condition3) return "當(dāng)前沒(méi)有可用房間";
return "數(shù)據(jù)加載中";

雖然不嵌套的三元選擇符很簡(jiǎn)單,但是在例如jsx的模版中,仍然不建議大量使用三元選擇符,因?yàn)榭赡軙?huì)出現(xiàn)如下代碼:

return (
    condition1 ? (
        <div className={condition2 ? cls1 : cls2}>
            {condition3 ? "111" : "222"}
            {condition4 ? (
                <Component prop1={condition5 ? a : b} />
            ) : null
        </div>
    ) : (
        <Component2>
            {condition6 ? children1 : children2}
        </Component2>
    )
)

類似的代碼在我們的項(xiàng)目中頻繁出現(xiàn),模版中大量的三元選擇符導(dǎo)致文件內(nèi)容拉得很長(zhǎng),很容易看著看著就不記得自己在哪個(gè)邏輯分支上了。

像這種簡(jiǎn)單的三元選擇符,做成一個(gè)簡(jiǎn)單的memo變量,哪怕是在組件內(nèi)直接寫變量定義(例如:const clsName = condition2 ? cls1 : cls2),最終到模板的可讀性也會(huì)比上述代碼高。

7. 邏輯不拆分

React hooks可以很方便地幫助開(kāi)發(fā)者聚合邏輯抽離成自定義hooks,千萬(wàn)不要把一個(gè)頁(yè)面所有的useState、useEffect等全都放在一個(gè)文件中:

圖片圖片

其實(shí)從功能上可以對(duì)頁(yè)面進(jìn)行拆分,拆分之后這些變量的定義也就可以拆出去了。

其中有一個(gè)很簡(jiǎn)單的原則就是,如果一個(gè)邏輯同時(shí)涉及到了useState和useEffect,那么就可以一并抽離出去成為一個(gè)自定義hooks。

例如接口請(qǐng)求大家一般都是直接在業(yè)務(wù)邏輯中做:

const Comp = () => {
    const [data, setData] = useState({});
    const [loading, setLoading] = useState(false);
    
    useEffect(() => {
        setLoading(true);
        queryData()
            .then((response) => {
                setData(response);
            })
            .catch((error) => {
                console.error(error);
            })
            .finally(() => {
                setLoading(false);
            });
    });
    
    if (loading) return "loading...";
    
    return <div>{data.text}</div>;
}

根據(jù)上面的原則,和數(shù)據(jù)拉取相關(guān)的內(nèi)容涉及到了useState和useEffect,這整塊邏輯就可以拆出去,那么最終就只剩下:

const Comp = () => {
    const { data, loading } = useQueryData();
    
    if (loading) return "loading...";
    
    return <div>{data.text}</div>;
};

這樣下來(lái),Comp組件就變得身份清爽了。

大家可以參考阿里的ahooks庫(kù),里面收集了很多前端常用的hooks,可以極大提升開(kāi)發(fā)效率和減少重復(fù)代碼。

8. 隨意讀取window對(duì)象的值

作為大型項(xiàng)目,很容易需要依賴別的模板掛載到window對(duì)象的內(nèi)容,讀取的時(shí)候需要考慮到是否有可能拿不到window對(duì)象上的內(nèi)容,從而導(dǎo)致js報(bào)錯(cuò)?例如:

window.tmeXXX.a.func();

如果這個(gè)tmeXXX所在的js加載失敗了,或者是某個(gè)版本中沒(méi)有a這個(gè)屬性或者func這個(gè)函數(shù),那么頁(yè)面就會(huì)白屏。

本文轉(zhuǎn)載自微信公眾號(hào)「沐灑」,作者「ASCII26」,可以通過(guò)以下二維碼關(guān)注。

責(zé)任編輯:武曉燕 來(lái)源: ASCII26
相關(guān)推薦

2023-12-05 15:58:06

React開(kāi)發(fā)

2021-11-04 08:53:00

if-else代碼Java

2025-03-26 00:12:00

C#重構(gòu)代碼

2021-05-07 07:31:33

數(shù)據(jù)分析互聯(lián)網(wǎng)運(yùn)營(yíng)大數(shù)據(jù)

2022-05-10 10:28:21

JavaScript代碼

2011-06-09 13:48:48

程序員

2022-10-27 11:36:59

map函數(shù)對(duì)象

2023-11-20 13:52:00

Redis數(shù)據(jù)庫(kù)

2023-08-09 14:01:55

2022-05-11 07:50:15

React UI組件庫(kù)前端

2022-06-13 09:00:33

React 項(xiàng)目前端

2010-09-09 08:39:30

2016-07-05 14:09:02

AndroidJAVA內(nèi)存

2010-08-24 09:49:44

2021-08-02 10:46:02

云計(jì)算用途

2021-04-25 11:31:45

React代碼整潔代碼的實(shí)踐

2013-08-08 10:19:22

2020-05-28 13:33:30

React Hook前端開(kāi)發(fā)

2020-06-12 08:34:37

React開(kāi)發(fā)工具

2022-10-10 09:00:35

ReactJSX組件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)