一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - React - 編寫簡潔React組件的小技巧

編寫簡潔React組件的小技巧

2022-02-25 16:14KooFE前端團隊 React

這篇文章主要介紹了編寫簡潔React組件的小技巧,幫助大家更好的理解和學習使用React,感興趣的朋友可以了解下

本文源于翻譯文章 Simple tips for writing clean React components, 原文作者 Iskander Samatov

在這篇文章中,我們會回顧一些簡單的技巧,它們將幫助我們編寫更簡潔的 React 組件,并且更好地擴展我們的項目。

避免使用擴展操作符傳遞 props

首先,讓我們從一個應該避免的反模式開始。除非有明確的理由這樣做,否則應該避免在組件樹中使用擴展操作符傳遞props,比如:{ ...props }。

通過這種方式傳遞 props 確實可以更快的編寫組件。但這也使得我們很難去定位代碼中的 bug。會使我們對編寫的組件失去信心,會使得我們重構組件變得更加困難,而且可能會導致出現很難排查的 bug。

將函數參數封裝成一個對象

如果函數接收多個參數,最好將它們封裝成一個對象。舉個例子:

?
1
2
3
export const sampleFunction = ({ param1, param2, param3 }) => {
  console.log({ param1, param2, param3 });
}

以這種方式編寫函數簽名有幾個顯著的優點:

  1. 你不用再擔心參數傳遞的順序。我曾犯過幾次因函數傳參順序問題而產生了 bug 的錯誤。
  2. 對于配置了智能提示的編輯器(現在的大多數都有),可以很好地完成函數參數的自動填充。

對于事件處理函數,將該處理函數作為函數的返回值

如果你熟悉函數式編程,這種編程技術類似于函數柯里化,因為已經提前設置了一些參數。

我們來看看這個例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react'
 
export default function SampleComponent({ onValueChange }) {
 
  const handleChange = (key) => {
    return (e) => onValueChange(key, e.target.value)
  }
 
  return (
    <form>
      <input onChange={handleChange('name')} />
      <input onChange={handleChange('email')} />
      <input onChange={handleChange('phone')} />
    </form>
  )
}

如您所見,以這種方式編寫處理程序函數,可以使組件樹保持簡潔。

組件渲染使用 map 而非 if/else

當你需要基于自定義邏輯呈現不同的元素時,我建議使用使用 map 而非 if/else 語句。

下面是一個使用if/else的示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react'
 
const Student = ({ name }) => <p>Student name: {name}</p>
const Teacher = ({ name }) => <p>Teacher name: {name}</p>
const Guardian = ({ name }) => <p>Guardian name: {name}</p>
 
export default function SampleComponent({ user }) {
  let Component = Student;
  if (user.type === 'teacher') {
    Component = Teacher
  } else if (user.type === 'guardian') {
    Component = Guardian
  }
 
  return (
    <div>
      <Component name={user.name} />
    </div>
  )
}

下面是一個使用map的示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react'
 
const Student = ({ name }) => <p>Student name: {name}</p>
const Teacher = ({ name }) => <p>Teacher name: {name}</p>
const Guardian = ({ name }) => <p>Guardian name: {name}</p>
 
const COMPONENT_MAP = {
  student: Student,
  teacher: Teacher,
  guardian: Guardian
}
 
export default function SampleComponent({ user }) {
  const Component = COMPONENT_MAP[user.type]
 
  return (
    <div>
      <Component name={user.name} />
    </div>
  )
}

使用這個簡單的小策略,可以使你的組件變得更具有可讀性,更容易理解。而且它還使邏輯擴展變得更簡單。

Hook組件

只要不濫用,這個模式是很有用的。

你可能會發現自己在應用中使用了很多組件。如果它們需要一個狀態來發揮作用,你可以將他們封裝為一個 hook 提供該狀態。這些組件的一些好例子是彈出框、toast 通知或簡單的 modal 對話框。例如,下面是一個用于簡單確認對話框的 hook 組件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import React, { useCallback, useState } from 'react';
import ConfirmationDialog from 'components/global/ConfirmationDialog';
 
export default function useConfirmationDialog({
  headerText,
  bodyText,
  confirmationButtonText,
  onConfirmClick,
}) {
  const [isOpen, setIsOpen] = useState(false);
 
  const onOpen = () => {
    setIsOpen(true);
  };
 
  const Dialog = useCallback(
    () => (
      <ConfirmationDialog
        headerText={headerText}
        bodyText={bodyText}
        isOpen={isOpen}
        onConfirmClick={onConfirmClick}
        onCancelClick={() => setIsOpen(false)}
        confirmationButtonText={confirmationButtonText}
      />
    ),
    [isOpen]
  );
 
  return {
    Dialog,
    onOpen,
  };
}

你可以像這樣使用 hook 組件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from "react";
import { useConfirmationDialog } from './useConfirmationDialog'
 
function Client() {
  const { Dialog, onOpen } = useConfirmationDialog({
    headerText: "Delete this record?",
    bodyText:
      "Are you sure you want delete this record? This cannot be undone.",
    confirmationButtonText: "Delete",
    onConfirmClick: handleDeleteConfirm,
  });
 
  function handleDeleteConfirm() {
    //TODO: delete
  }
 
  const handleDeleteClick = () => {
    onOpen();
  };
 
  return (
    <div>
      <Dialog />
      <button onClick={handleDeleteClick} />
    </div>
  );
}
 
export default Client;

以這種方式提取組件可以避免編寫大量狀態管理的樣板代碼。如果你想了解更多 React hooks,請查看 我的帖子

組件拆分

下面三個技巧是關于如何巧妙地拆分組件。根據我的經驗,保持組件的簡潔是保持項目可管理的最佳方法。

使用包裝器

如果你正在努力尋找一種方法來拆分復雜組件,看看你的組件中每個元素所提供的功能。有些元素提供了獨特的功能,比如拖拽功能。

下面是一個使用react-beautiful-dnd實現拖拽的組件示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React from 'react'
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
export default function DraggableSample() {
  function handleDragStart(result) {
    console.log({ result });
  }
  function handleDragUpdate({ destination }) {
    console.log({ destination });
  }
  const handleDragEnd = ({ source, destination }) => {
    console.log({ source, destination });
  };
  return (
    <div>
      <DragDropContext
        onDragEnd={handleDragEnd}
        onDragStart={handleDragStart}
        onDragUpdate={handleDragUpdate}
      >
        <Droppable
          droppableId="droppable"
          direction="horizontal"
        >
          {(provided) => (
            <div {...provided.droppableProps} ref={provided.innerRef}>
              {columns.map((column, index) => {
                return (
                  <ColumnComponent
                    key={index}
                    column={column}
                  />
                );
              })}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    </div>
  )
}

現在,看一下在我們將所有拖拽邏輯移到包裝器之后的組件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react'
export default function DraggableSample() {
  return (
    <div>
      <DragWrapper>
      {columns.map((column, index) => {
        return (
          <ColumnComponent key={index} column={column}/>
        );
      })}
      </DragWrapper>
    </div>
  )
}

下面是包裝器的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from 'react'
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
export default function DragWrapper({children}) {
  function handleDragStart(result) {
    console.log({ result });
  }
  function handleDragUpdate({ destination }) {
    console.log({ destination });
  }
  const handleDragEnd = ({ source, destination }) => {
    console.log({ source, destination });
  };
  return (
    <DragDropContext
      onDragEnd={handleDragEnd}
      onDragStart={handleDragStart}
      onDragUpdate={handleDragUpdate}
    >
      <Droppable droppableId="droppable" direction="horizontal">
        {(provided) => (
          <div {...provided.droppableProps}  ref={provided.innerRef}>
            {children}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  )
}

因此,可以更直觀地看到組件在更高層次上的功能。所有用于拖拽的功能都在包裝器中,使得代碼更容易理解。

關注點分離

這是我最喜歡的拆分較大組件的方法。

從 React 角度出發,關注點的分離意味著分離組件中負責獲取和改變數據的部分和純粹負責顯示元素的部分。

這種分離關注點的方法是引入 hooks 的主要原因。你可以用自定義 hook 封裝所有方法或全局狀態連接的邏輯。

例如,讓我們看看如下組件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from 'react'
import { someAPICall } from './API'
import ItemDisplay from './ItemDisplay'
export default function SampleComponent() {
  const [data, setData] = useState([])
  useEffect(() => {
    someAPICall().then((result) => { setData(result)})
  }, [])
  function handleDelete() { console.log('Delete!'); }
  function handleAdd() { console.log('Add!'); }
  const handleEdit = () => { console.log('Edit!'); };
  return (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)}
      </div>
      <div>
        <button onClick={handleDelete} />
        <button onClick={handleAdd} />
        <button onClick={handleEdit} />
      </div>
    </div>
  )
}

下面是它的重構版本,使用自定義hook拆分后的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react'
import ItemDisplay from './ItemDisplay'
export default function SampleComponent() {
  const { data, handleDelete, handleEdit, handleAdd } = useCustomHook()
  return (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)}
      </div>
      <div>
        <button onClick={handleDelete} />
        <button onClick={handleAdd} />
        <button onClick={handleEdit} />
      </div>
    </div>
  )
}

這是該 hook 本身的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
import { someAPICall } from './API'
export const useCustomHook = () => {
  const [data, setData] = useState([])
  useEffect(() => {
    someAPICall().then((result) => { setData(result)})
  }, [])
  function handleDelete() { console.log('Delete!'); }
  function handleAdd() { console.log('Add!'); }
  const handleEdit = () => { console.log('Edit!'); };
  return { handleEdit, handleAdd, handleDelete, data }
}

每個組件封裝為一個單獨的文件

通常大家會這樣寫代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react'
export default function SampleComponent({ data }) {
  const ItemDisplay = ({ name, date }) => (
    <div>
      <h3>{name}</h3>
      <p>{date}</p>
    </div>
  )
  return (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)}
      </div>
    </div>
  )
}

雖然用這種方式編寫 React 組件沒有什么大問題,但這并不是一個好的做法。將 ItemDisplay 組件移動到一個單獨的文件可以使你的組件松散耦合,易于擴展。

在大多數情況下,要編寫干凈整潔的代碼,需要注意并花時間遵循好的模式和避免反模式。因此,如果你花時間遵循這些模式,它有助于你編寫整潔的 React 組件。我發現這些模式在我的項目中非常有用,希望你也這么做!

以上就是編寫簡潔React組件的小技巧的詳細內容,更多關于編寫React組件的技巧的資料請關注服務器之家其它相關文章!

原文鏈接:https://juejin.cn/post/6947676213175386126

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 全黄h全肉细节文在线观看 全彩成人18h漫画 | 国产精品视频网 | 99久久精品久久久久久清纯 | 久久精麻豆亚洲AV国产品 | 激情男人天堂 | 大好硬好深好爽想要视频 | 91av爱爱| 国产精品久热 | 国产伊人久久 | 强制高h| 互换身体全集免费观看 | 2021国产麻豆剧传媒新片 | 亚洲香蕉伊在人在线观看9 亚洲系列国产系列 | 女女性恋爱免费 | 成人高清视频在线观看 | 好大好湿好硬好爽好深免费视频 | 亚洲午夜精品久久久久久人妖 | 国产欧美视频在线观看 | 邪恶肉肉全彩色无遮盖 | 日本人黄色 | 香蕉 在线播放 | 男人晚上适合偷偷看的污污 | 国产无套在线播放 | 2018天天拍拍拍免费视频 | 毛片手机在线视频免费观看 | 免费国产影视观看网站入口 | 国产精品国语自产拍在线观看 | 亚洲好骚综合 | 青青青国产精品国产精品久久久久 | 插入影院| 黄动漫车车好快的车车a | 99久久精品无码一区二区毛片 | 精品国产福利片在线观看 | 窝窝影院午夜色在线视频 | 天天成人| 亚洲国产在 | 久久精品国产视频澳门 | japanese秘书丝袜 | 失禁尿丝袜vk | 天生奶水1v1高h | 成人涩涩屋福利视频 |