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

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

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

服務器之家 - 編程語言 - JavaScript - React - React.cloneElement的使用詳解

React.cloneElement的使用詳解

2022-02-23 16:16fullstackbb React

因為要接手維護一些項目,團隊的技術棧最近從 vue 轉向 react ,作為一個 react 新手,加上一向喜歡通過源碼來學習新的東西,就選擇了通過閱讀 antd 這個大名鼎鼎的項目源碼來學習一些 react 的用法。

因為要接手維護一些項目,團隊的技術棧最近從 vue 轉向 react ,作為一個 react 新手,加上一向喜歡通過源碼來學習新的東西,就選擇了通過閱讀 antd 這個大名鼎鼎的項目源碼來學習一些 react 的用法。

在閱讀源碼的過程中,發(fā)現(xiàn)好些組件都使用了 React.cloneElement 這個 api ,雖然通過名字可以猜測它做了什么,但是并不知道具體的作用;然后去看官方文檔,文檔很清晰地描述了它的作用,卻沒有告訴我們什么場景下需要使用它。于是我根據(jù)文檔的描述,結合源碼的使用,面向 google 和 stackoverflow,總結出來一些使用場景。

cloneElement 的作用

?
1
2
3
4
5
React.cloneElement(
 element,
 [props],
 [...children]
)

首先看一下官方文檔對這個 API 的描述:

Clone and return a new React element using element as the starting point. The resulting element will have the original element's props with the new props merged in shallowly. New children will replace existing children. key and ref from the original element will be preserved.

總結下來就是:

  1. 克隆原來的元素,返回一個新的 React 元素;
  2. 保留原始元素的 props,同時可以添加新的 props,兩者進行淺合并;
  3. key 和 ref 會被保留,因為它們本身也是 props ,所以也可以修改;
  4. 根據(jù) react 的源碼,我們可以從第三個參數(shù)開始定義任意多的子元素,如果定義了新的 children ,會替換原來的 children ;

使用場景

根據(jù)上面的定義分解,我們可以在不同的場景下根據(jù)需要來使用這個 api 。

添加新的 props

當我們創(chuàng)建一個通用組件時,根據(jù)內(nèi)部的邏輯,想要給每個子元素添加不同的類名,這個時候我們可以修改它的 className

假設我們有一個 Timeline 組件,允許我們根據(jù)需要定義多個 TimelineItem ,在內(nèi)部我們想要給最后一個TimelineItem 添加一個 timeline-item-last 類來渲染特殊的效果,這個時候我們可以這樣做:

?
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
const MyTimeline = () => {
 return (
  <Timeline>
   <TimelineItem>2020-06-01</TimelineItem>
   <TimelineItem>2020-06-08</TimelineItem>
   <TimelineItem>2020-07-05</TimelineItem>
  </Timeline>
 )
}
 
// 在 Timeline 內(nèi)部,邏輯可能是這樣的
import class from 'classnames';
const Timeline = props => {
 // ...
 // ...
 const itemCount = React.children.count(props.children);
 const items = React.children.map(props.children, (item, index) => {
  return React.cloneElement(item, {
   className: class([
    item.props.className,
    'timeline-item',
    index === count - 1 ? 'timeline-item-last' : ''
   ])
  })
 }
 return <div className={'timeline'}>{ items }</div>
}

除了添加 className ,還可以動態(tài)給子組件添加更多的 props 信息,react-router Switch 會給匹配的子組件添加 locationcomputedMatch 信息:

?
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
class Switch extends React.Component {
 render() {
  return (
   <RouterContext.Consumer>
    {context => {
     invariant(context, "You should not use <Switch> outside a <Router>");
 
     const location = this.props.location || context.location;
 
     let element, match;
 
     // We use React.Children.forEach instead of React.Children.toArray().find()
     // here because toArray adds keys to all child elements and we do not want
     // to trigger an unmount/remount for two <Route>s that render the same
     // component at different URLs.
     React.Children.forEach(this.props.children, child => {
      if (match == null && React.isValidElement(child)) {
       element = child;
 
       const path = child.props.path || child.props.from;
 
       match = path
        ? matchPath(location.pathname, { ...child.props, path })
        : context.match;
      }
     });
 
     return match
      ? React.cloneElement(element, { location, computedMatch: match })
      : null;
    }}
   </RouterContext.Consumer>
  );
 }
}

修改 props 的事件

假設我們有一個 Tab 組件,它下面包含多個 TabPane 子組件,我們想要點擊每個 TabPane 子組件的同時觸發(fā) Tab 的 onClick 事件,用戶自己本身可能給每個 TabPane 定義了獨立的 onClick 事件,這時候我們就要修改子組件 onClick 事件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
const Tab = props => {
 const { onClick } = props;
 const tabPanes = React.children.map(props.children, (tabPane, index) => {
  const paneClick = () => {
   onClick && onClick(index);
   tabPane.props?.onClick();
  }
  return React.cloneElement(tabPane, {
    onClick: paneClick,
  })
 })
 return <div>{ tabPanes }</div>
}

定制樣式

創(chuàng)建一個叫 FollowMouse 組件時,我們允許用戶定義內(nèi)容組件 Content ,當鼠標移動時,根據(jù)內(nèi)容的大小,自動計算 Content 的位置避免溢出屏幕,這個時候我們就可以使用 cloneElement 來動態(tài)修改它的樣式。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 簡單起見,這里省略鼠標事件。
const FollowMouse = props => {
 const { Content } = props;
 const customContent = React.isValidElement ? Content : <span>{ Content }</span>
 const getOffset = () => {
  return {
   position: 'absolute',
   top: ...,
   left: ...,
  }
 }
 const renderContent = React.cloneElement(custonContent, {
  style: {
   ...getOffset()
  }
 })
 return <div>{ renderContent() }</div>
}

添加 key

當我們創(chuàng)建一個元素列表時,可以通過 cloneElement 給每個節(jié)點添加一個 key 。

?
1
2
3
4
5
6
const ComponentButton = props => {
 const { addonAfter, children } = props;
 const button = <button key='button'>{ children }</button>
 const list = [button, addonAfter ? React.cloneElement(addonAfter, { key: 'button-addon' } : null)
 return <div>{ list } <div>
}

總結

在開發(fā)復雜組件中,經(jīng)常會根據(jù)需要給子組件添加不同的功能或者顯示效果,react 元素本身是不可變的 (immutable) 對象, props.children 事實上并不是 children 本身,它只是 children 的描述符 (descriptor) ,我們不能修改任何它的任何屬性,只能讀到其中的內(nèi)容,因此 React.cloneElement 允許我們拷貝它的元素,并且修改或者添加新的 props 從而達到我們的目的。

當然,得益于 react 強大的組合模式,這并不僅僅局限于 props.children ,不管是 props.left 還是 props.right 或者任何其它的 props 傳進來的內(nèi)容,只要是合法的 react 元素,我們都可以使用這個 React.cloneElement 對其進行操作。

以上就是React.cloneElement的使用詳解的詳細內(nèi)容,更多關于React.cloneElement的使用的資料請關注服務器之家其它相關文章!

原文鏈接:https://fullstackbb.com/react/when-to-use-react-cloneelement/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 农夫69小说小雨与农村老太 | 五月一区二区久久综合天堂 | 亚洲久草在线 | 欧美一区二区三区在线观看免费 | 成人亚洲欧美综合 | japanese在线观看 | 男女车车好快的车车免费网站 | 天堂8在线天堂资源bt | pregnantsexxx临盆孕妇| 操穴勤| 亚洲男人的天堂网 | 欧美高清在线 | 日韩一卡2卡3卡新区网站 | 成功精品影院 | 国产免费看片 | 日韩国产欧美视频 | 精品卡1卡2卡三卡免费视频 | jzjzjz日本在线观看 | 精品卡1卡2卡三卡免费视频 | 四虎官网| 美女靠逼免费网站 | 帅小伙和警官同性3p | 国产有码在线 | 男男调教打屁股 | 农夫69小说小雨与农村老太 | 午夜熟女插插XX免费视频 | 果冻传媒在线播放观看w | 日韩不卡一区二区三区 | 欧美老肥妇bbb | 91欧美秘密入口 | 亚洲国产一区二区三区青草影视 | 欧美在线欧美 | 国产在线精品亚洲第一区香蕉 | 大又大又黄又爽免费毛片 | 校花被吃奶还摸下面 | 国产在线三级 | 国产一级片免费视频 | 精品国产免费一区二区三区 | 亚洲欧美日韩国产一区二区精品 | 国产小视频在线播放 | 91制片|