激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产一区精品在线观看 | 日韩视频在线观看免费 | 三级xxxx | 欧美男人天堂网 | 日日草天天干 | 国产亚洲精品久久久闺蜜 | 成人mm视频在线观看 | 国产精品视频在 | 国产午夜精品久久久久久久蜜臀 | 欧美有码在线观看 | 中文字幕在线观看视频www | 亚洲国产成人一区二区 | 国产一级毛片av | 欧美18videos性处按摩 | av在线免费观看国产 | 久久经典国产视频 | 黄色特级毛片 | 日韩欧美中文字幕视频 | 欧美视频首页 | 国产伦久视频免费观看视频 | 久久精品亚洲欧美日韩精品中文字幕 | 广州毛片 | 成人国产精品齐天大性 | 毛片哪里看 | 久久99精品久久久久久小说 | 国产a级片电影 | 欧美日韩亚洲一区二区三区 | 欧美a∨一区二区三区久久黄 | 免费视频99 | 国产精品麻豆一区二区三区 | hd极品free性xxx一护士 | 亚洲视频在线网 | 免费毛片在线视频 | 亚洲白嫩在线观看 | 黄视频网址 | 精品国产乱码一区二区三区四区 | 亚洲第一色婷婷 | 久久亚洲精品视频 | 欧洲精品久久 | 久久免费精品 | av免费在线观看av |