簡體   English   中英

在React中迭代數據數組時渲染JSX元素的最有效方法

[英]Most efficient way of rendering JSX elements when iterating on array of data in React

我有一個包含對象的數組。 我正在創建此數組的映射以使用span組件呈現名稱。

let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];

我一直在使用以下兩個不同的功能來迭代該對象數組,並使用map來呈現JSX元素。

Functionality1:

import React, { Component } from 'react';
class App extends Component {

  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
    const items = data.map((key, i) => {
      return <span key={key.id}>{key.name}</span>;
    });
    return (
      <div>
        {items}
      </div>
    );
  }
}

export default App;

Functionality2:

import React, { Component } from 'react';
class App extends Component {

  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
    let rows = [];
    data.map((key, i) => {
      rows.push(<span key={key.id}>{key.name}</span>);
    });
    return (
      <div>
        {rows}
      </div>
    );
  }
}


export default App;

我知道上面兩種使用map和渲染JSX元素的方法。 除了這兩個之外,還有其他方法可以做同樣的事嗎? 如果是這樣,推薦哪個?

我會這樣做的

const data = [{id: 1, name: 'a'}, {id: 2, name: 'b'}];

export default class App extends PureComponent {
  render() {
    return (
      <div>
        {data.map(({ id, name }) => <span key={id}>{name}</span>)}
      </div>
    );
  }
}

現在,您的data不會在每次渲染時重新實例化,並且您不必垃圾收集任何不必要的變量聲明。

大多數情況下,我遵循這條規則:

創建一個呈現項目的組件

// in some file
export const RenderItems = ({data}) => {
  return data && data.map((d, i) => <span key={d.id}>{d.name}</span>) || null
}

鈎住RenderItems

import { RenderItems } from 'some-file'

class App extends Component {
  render() {
    // you may also define data here instead of getting data from props
    const { data } = this.props
    return (
      <div>
        <RenderItems data={data} />
      </div>
    )
  }
}

將數據附加到組件中

const data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}]
<App data={data} />

即使使用第二個代碼示例,遵循此規則也不會影響性能。 推送數組中的項目並呈現項目。 因為,你不是直接在渲染鈎子里工作。 始終注意渲染鈎子不會直接在其中實現任何邏輯。


此外,我不會為使用密鑰創建id

const data = [{"name": "Hi"}, {"name": "Hello"}]
//... and when using index as key
.map((d, i) => <span key={'item-'+i}>
// or,
.map((d, i) => <span key={'item-'+i+'-'+d.name}>

看到這篇文章為什么我在使用index作為鍵時遵循這種語法。


更新:

如果要避免使用不必要的html標記,可以使用React.Fragment

export const RenderItems = ({data}) => {
  return data && 
    data.map(
      (d, i) => <React.Fragment key={d.id}>{d.name}</React.Fragment>
    ) || null
}
// and when rendering, you just return the component
return <RenderItems data={data} />

注意:

  1. 只有當您沒有任何其他屬性時,才能使用<></>作為<React.Fragment></React.Fragment>的別名。 因為我們正在使用它的關鍵屬性,而不是使用它。
  2. 看看這個 ,以支持React.Fragment簡短表示法。

使用<></>示例:

<>{d.name}</>

這將在沒有任何標記的html中呈現d.name的值。 當我們專門改造現有設計以應對應用時,這被認為是最好的。 或者,可能還有其他情況。 就像,我們將顯示一個定義列表:

<dl>
  <dt></dt>
  <dd></dd>
  <dt></dt>
  <dd></dd>
  <dt></dd>
</dl>

我們不想附加不必要的html標簽,然后使用Fragment將使我們的生活更輕松:

例:

<>
  <dt>{d.term}</dt>
  <dd>{d.definition}</dd>
</>

最重要的情況是在tr (TR組件)中渲染td元素。 如果我們不這樣做,那么我們就違反了HTML的規則。 組件將無法正確呈現。 在反應中,它會給你一個錯誤。

UPDATE2:

此外,如果你有很長的道具列表,如下所示:

const {
  items,
  id,
  imdbID,
  title,
  poster,
  getMovieInfo,
  addToFavorites,
  isOpen,
  toggleModal,
  closeModal,
  modalData,
} = props

您可以考慮解構如下:

const { items, ...other } = props
// and in your component you can use like:
<div modalData={other.modalData}>

但是,我個人更喜歡使用第一個示例代碼。 這是因為在開發過程中我不需要回顧其他組件或者每次都尋找控制台。 在給定的例子中,有像modalData={}這樣的鍵,所以我們很容易維護modalData={other.modalData} 但是,如果像<div>{modalData}</div>這樣的代碼需要怎么辦? 那么,您也可能同意我的偏好。

第一種方式更好。

  1. Array.prototype.map在幕后創建一個數組,並在對每個元素應用修改后返回它。 Functionality-1創建兩個數組,而Functionality-2創建三個數組。

  2. 功能-1讀得更好。 這就是React代碼通常被編寫的方式。 對於這樣一個簡單的元素,我會保存物品常量的定義 ,並把地圖聲明的JSX 直接返回。

通常, forwhile語句是迭代數組的最有效方法。 在非關鍵位置處理小陣列的方式可以被認為是微優化。

在React組件中使用map是慣用的,因為它足夠快並且可以將值作為表達式的一部分返回。

雖然這是一個反模式:

let rows = [];
data.map((key, i) => {
  rows.push(<span key={key.id}>{key.name}</span>);
});

map應該將數組元素映射到其他值(因此名稱),而不是迭代數組而不是forEach或其他循環。 可以使用ESLint array-callback-return規則跟蹤此問題。

該組件是無狀態的,不需要是Component類。 它可以是功能組件或PureComponent類。 由於data是常量,因此不需要在每個渲染上分配:

const data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];

const App = props => <div>
  {data.map(({ id, name }) => <span key={id}>{name}</span>)}
</div>;

第一種方法是正確的。 使用map函數迭代數組。

 export default class App extends React.Component{ constructor(props){ super(props); this.state = { data: [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}]; }; } render(){ return( <div> {this.state.data.map((data,index)=> <span key={data.id}>{data.name}</span> )} ); } } 

我會與去mapreturn(...)作為地圖返回數組。 它更干凈,更易讀,是我個人追求的。

要添加答案,如果數組data可能在通道中發生變化,那么我將創建一個新的無狀態轉儲組件:

const Spanner = props => { return <span key={ props.data.id }>{ props.data.name }</span> };

class App extends Component {
  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
      return (
        <div>
          { 
            data.map( (item, ind) => {
              return (<Spanner key={item.id} data={item.name} />);
            })
          }
        </div>
      );
    }
  }
}

這樣我們就可以將此Spanner組件用作不同組件之間共享的公共組件。 如果data隨時間變化(大部分時間都是這樣),您可以向Spanner組件編寫包裝函數,並在需要的地方調用新函數。 data=[{"id": "01", "name": "Hi", "userType": "Admin"}, {"id": "02", "name": "Hello", "userType": "Client"}];

const UserWidget = (props) => {
  return (
    <div>
      <h4>{ props.type }</h4>
      <Spanner key={ props.key } data={ props.name }/>
    </div>
  );
}
// now both the UserWidget and the Spanner Components can be used wherever required
// say a dashboard Component wants to use the UserWidget
class Dashboard extends Component {
  render() {
    let data = [{"id": "01", "name": "Hi", "userType": "Admin"}, {"id": "02", "name": "Hello", "userType": "Client"}];
      return (
        <div>
          { 
            data.map( (item, ind) => {
              return (<UserWidget type={ item.userType } key={item.id} data={item.name} />);
            })
          }
        </div>
      );
    }
  }
}

這樣您就不會重復自己,即使現在新data數組具有新的關鍵userType ,您的應用程序組件仍然具有預期的行為。 這就是我如何做到的。

您可以使用它來獲得最佳理解

 const data = [{id: 1, name: 'a'}, {id: 2, name: 'b'}];

export default class App extends React.Component {
  render() {
    return (
      <div>
        {data.map((data, dataIndex ) => <span key={dataIndex}>{data.name}</span>)}
      </div>
    );
  }
}

在這里,您可以理解該名稱屬於with屬性。

toSpan的功能可以重復使用。

class App extends React.Component {
  render() {
    const data = [{id: `01`, name: `Hi`}, {id: `02`, name: `Hello`}]
    const toSpan = ({id, name}) => <span key={id}>{name}</span>
    return (
      <div>{data.map(toSpan)}</div>
    )
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM