[英]Most efficient way of rendering JSX elements when iterating on array of data in React
I have an array which contains objects. 我有一个包含对象的数组。 I am creating a map of this array to renders the names with a span
component. 我正在创建此数组的映射以使用span
组件呈现名称。
let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
I have been using the below two different functionalities to iterate on that array of objects, and using map to render JSX elements. 我一直在使用以下两个不同的功能来迭代该对象数组,并使用map来呈现JSX元素。
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;
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;
I known to the above two different ways of using map
and rendering JSX elements. 我知道上面两种使用map
和渲染JSX元素的方法。 Is there any other ways of doing the same, apart from these two? 除了这两个之外,还有其他方法可以做同样的事吗? If so, which is recommended? 如果是这样,推荐哪个?
I would do this 我会这样做的
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>
);
}
}
Now, your data
is not reinstantiated on every render, and you don't have to garbage collect any unnecessary variable declarations. 现在,您的data
不会在每次渲染时重新实例化,并且您不必垃圾收集任何不必要的变量声明。
Mostly, I follow this rule: 大多数情况下,我遵循这条规则:
Create a component which renders the items 创建一个呈现项目的组件
// in some file
export const RenderItems = ({data}) => {
return data && data.map((d, i) => <span key={d.id}>{d.name}</span>) || null
}
Hook the RenderItems 钩住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>
)
}
}
Attach the data in the component 将数据附加到组件中
const data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}]
<App data={data} />
Following this rule will not impact on performance even with your second example of code ie. 即使使用第二个代码示例,遵循此规则也不会影响性能。 pushing items in an array and rendering the items. 推送数组中的项目并呈现项目。 Because, you're not directly working inside the render hook. 因为,你不是直接在渲染钩子里工作。 Always take care that render hook wouldn't implement any logic inside it directly. 始终注意渲染钩子不会直接在其中实现任何逻辑。
Further, I wouldn't create id
just for using key: 此外,我不会为使用密钥创建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}>
See this post why I follow this syntax while using index as key. 看到这篇文章为什么我在使用index作为键时遵循这种语法。
If you want to avoid unnecessary html tags being used, you can use React.Fragment 如果要避免使用不必要的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} />
Note: 注意:
<></>
as an alias for <React.Fragment></React.Fragment>
only if you don't have any additional property. 只有当您没有任何其他属性时,才能使用<></>
作为<React.Fragment></React.Fragment>
的别名。 Since we're using key property on it, not using it. 因为我们正在使用它的关键属性,而不是使用它。 React.Fragment
. 看看这个 ,以支持React.Fragment
简短表示法。 Example using <></>
: 使用<></>
示例:
<>{d.name}</>
This will be rendered d.name
's value in html without any tag. 这将在没有任何标记的html中呈现d.name
的值。 This is considered best when we specifically transform our existing design to react application. 当我们专门改造现有设计以应对应用时,这被认为是最好的。 Or, there might be other cases. 或者,可能还有其他情况。 Like, we are going to display a definition list: 就像,我们将显示一个定义列表:
<dl>
<dt></dt>
<dd></dd>
<dt></dt>
<dd></dd>
<dt></dd>
</dl>
And we don't want to attach unnecessary html tag, then using Fragment will make our life easier: 我们不想附加不必要的html标签,然后使用Fragment将使我们的生活更轻松:
Example: 例:
<>
<dt>{d.term}</dt>
<dd>{d.definition}</dd>
</>
The most important case will be for rendering td
element in tr
(a TR component). 最重要的情况是在tr
(TR组件)中渲染td
元素。 If we don't, then we're breaking the rule of HTML. 如果我们不这样做,那么我们就违反了HTML的规则。 The component will not be rendered properly. 组件将无法正确呈现。 In react, it will throw you an error. 在反应中,它会给你一个错误。
Also, if you have long list of props like below: 此外,如果你有很长的道具列表,如下所示:
const {
items,
id,
imdbID,
title,
poster,
getMovieInfo,
addToFavorites,
isOpen,
toggleModal,
closeModal,
modalData,
} = props
You may consider destructuring like: 您可以考虑解构如下:
const { items, ...other } = props
// and in your component you can use like:
<div modalData={other.modalData}>
But, personally I prefer using first example code. 但是,我个人更喜欢使用第一个示例代码。 It's because while developing I won't need to look back to other component or look for the console each and every time. 这是因为在开发过程中我不需要回顾其他组件或者每次都寻找控制台。 In the given example there's key like modalData={}
so we easily maintain modalData={other.modalData}
. 在给定的例子中,有像modalData={}
这样的键,所以我们很容易维护modalData={other.modalData}
。 But what if it is needed to code like <div>{modalData}</div>
? 但是,如果像<div>{modalData}</div>
这样的代码需要怎么办? Then, you may also agree with my preference. 那么,您也可能同意我的偏好。
The first way is better. 第一种方式更好。
Array.prototype.map
creates an array behind the scenes and returns it after applying the modification on each element. Array.prototype.map
在幕后创建一个数组,并在对每个元素应用修改后返回它。 Functionality-1 creates two arrays, while Functionality-2 creates three. Functionality-1创建两个数组,而Functionality-2创建三个数组。
Functionality-1 reads better. 功能-1读得更好。 It's how React code usually being written. 这就是React代码通常被编写的方式。 For a simple element like this, I'd save the const definition for items and put the map statement in the JSX to be returned directly . 对于这样一个简单的元素,我会保存物品常量的定义 ,并把地图声明的JSX 直接返回。
Generally, for
or while
statement is the most efficient way to iterate an array. 通常, for
或while
语句是迭代数组的最有效方法。 The way a small array is processed in non-critical place can be considered microoptimisation. 在非关键位置处理小阵列的方式可以被认为是微优化。
The use of map
is idiomatic in React components because it's fast enough and can return a value as a part of an expression. 在React组件中使用map
是惯用的,因为它足够快并且可以将值作为表达式的一部分返回。
While this is an antipattern: 虽然这是一个反模式:
let rows = [];
data.map((key, i) => {
rows.push(<span key={key.id}>{key.name}</span>);
});
map
is supposed to map array elements to other values (hence the name), not to iterate an array instead of forEach
or other loop. map
应该将数组元素映射到其他值(因此名称),而不是迭代数组而不是forEach
或其他循环。 This problem can be tracked with ESLint array-callback-return
rule. 可以使用ESLint array-callback-return
规则跟踪此问题。
The component is stateless and doesn't need to be Component
class. 该组件是无状态的,不需要是Component
类。 It can be functional component or PureComponent
class. 它可以是功能组件或PureComponent
类。 Since data
is constant, it doesn't need to be assigned on each render: 由于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>;
the first method is correct. 第一种方法是正确的。 use the map function to iterate through the array. 使用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> )} ); } }
I'd go with the map
inside the return(...)
as map returns an array. 我会与去map
内return(...)
作为地图返回数组。 It's cleaner and readable, something I personally strive for. 它更干净,更易读,是我个人追求的。
To add on to the answer, if the array data
might change down the lane I'd go with creating a new stateless dump component: 要添加答案,如果数组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>
);
}
}
}
This way we can use this Spanner Component as a common component shared among different component. 这样我们就可以将此Spanner组件用作不同组件之间共享的公共组件。 And in case the data
changes over time ( which most of the time, does) you can write a wrapper function to the Spanner component and call the new function wherever required. 如果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>
);
}
}
}
This way you're not repeating yourself, and your App Component still has the expected behavior even if now the new data
array has the new key userType
. 这样您就不会重复自己,即使现在新data
数组具有新的关键userType
,您的应用程序组件仍然具有预期的行为。 Again this is how I'd do it. 这就是我如何做到的。
You may use this for best understanding 您可以使用它来获得最佳理解
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>
);
}
}
Here you can understand that the name belongs to with attribute. 在这里,您可以理解该名称属于with属性。
The function toSpan
can be reused. 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.