react 后端渲染 React优化组件渲染(re-render)到哪个地步就算可以了?
问题用React函数式调用组件,感觉组件re-render次数过多。CodeSandBox不会打印出"Very slow component re-mounts" 算可以了?还是说"Very slow
顺晟科技
2021-06-16 10:29:55
217
当我问自己百次时,我正在研究一个典型的创建、读取、更新和删除屏幕:"我应该将状态保留在这个组件中还是将其移动到父组件?"。
如果需要对子组件的状态进行轻微控制。您可能也遇到了同样的问题。
让我们通过一个简单的例子和三种修复方法来回顾它。前两种方法是常见的做法,第三种方法不太常规。
问题;
为了向您展示我的意思,我将使用一个简单的书籍CRUD(译者注:增加(创建)、读取查询(检索)、更新(更新)和删除(删除))屏幕(如此简单,它没有创建和删除操作)。
381280250-5b 6a e 9839 a 548 _ article x . png
我们有三个组成部分BookList/是一个组件,显示了用于编辑它们的书籍和按钮列表BookForm/有两个输入和一个按钮,用于保存对书籍的更改。以及包含其他两个组件的BookApp/。
那么,我们的状态是什么?好吧,BookApp/应该跟踪书籍清单以及识别当前正在编辑的书籍的内容BookList/没有任何状态。并且BookForm/应该保持输入的当前状态,直到单击"保存"按钮。
导入反应,{组件}来自“反应”;
从" react-dom "导入{ render };
constbooks=[
{
标题:'企业安全,
author:'IsaacAsimov '
},
//.
];
constBookList=({books,onEdit})=gt .(
桌子
tr
thBookTitle/th
th/th
/tr
{books.map((book,index)=gt;(
tr
td{book.title}/td
任务描述
lt .buttonOnClick={()=gt;onEdit(index)}gt .编辑lt ./buttongt .
/td
/tr
))}
/table
);
classBookFormextendsComponent{
状态={.这个。道具。book };
render(){
if(!这个。道具。book)返回null
返回(
lt .表格gt .
h3Book/h3
lt .labelgt
标题:
lt .投入
value={this.state.title}
onChange={e=gt .这个。SetState({ title : e . target。值})}
/gt .
lt ./label gt。
lt .labelgt
Author:
lt .投入
value={this.state.author}
onChange={e=gt .这个。SetState({ author : e . target。值})}
/gt .
lt ./label gt。
lt .buttonOnClick={()=gt;this.props.onSave({.这个。state })} gt。
救援
lt ./buttongt .
lt ./formgt .
);
}
}
classBookAppextendsComponent{
状态={
书:本,
activeIndex:-1
};
render(){
const{books,activeIndex }=this.state
const active book=books[active index];
返回(
差异
lt .书单
书籍={books}
onEdit={index=gt .
this.setState({
活动索引:索引
})}
/gt .
lt .BookForm
book={activeBook}
onSave={book=gt .
this.setState({
books:Object.assign([.books],{[activeIndex]:book}),
activeIndex:-1
})}
/gt .
/div
);
}
}
渲染(lt;BookApp/gt .文档。getelementbyid(' root ');
在codesandbox尝试一下
看起来不错,但是他不起作用。
我们正在创建组件实例时初始化BookForm/状态,因此,当从列表中选择另一本书时,父级无法让它知道它需要更改它。
我们改如何修复它?
方法1:受控组件
一种常见的方法是将状态提升,将BookForm/转换为受控组件。我们删除BookForm/状态,将活性书添加到BookApp/状态,并向BookForm/添加一个待清扫房道具,我们在每次输入时都会调用它。
//.
classBookFormextendsComponent{
render(){
if(!这个。道具。book)返回null
返回(
lt .表格gt .
h3Book/h3
lt .labelgt
标题:
lt .投入
value={this.props.book.title}
onChange={e=gt .
this.props.onChange({
.这个。道具。书,
title:e.target.value
})}
/gt .
lt ./label gt。
lt .labelgt
Author:
lt .投入
value={this.props.book.author}
onChange={e=gt .
this.props.onChange({
.这个。道具。书,
author:e.target.value
})}
/gt .
lt ./label gt。
lt .buttonOnClick={()=gt;这个。道具。OnSave()} gt。保存lt ./buttongt .
lt ./formgt .
);
}
}
classBookAppextendsComponent{
状态={
书:本,
activeBook:null,
activeIndex:-1
};
render(){
const{books,activeBook,activeIndex }=this.state
返回(
差异
lt .书单
书籍={books}
onEdit={index=gt .
this.setState({
activeBook:{.书籍[索引]},
活动索引:索引
})}
/gt .
lt .BookForm
book={activeBook}
onChange={book=gt .这个。setstate({ active book : book })}
onSave={()=gt;
this.setState({
books:Object.assign([.books],{[activeIndex]:activeBook}),
activeBook:null,
activeIndex:-1
})}
/gt。
/div
);
}
}
//.
方法2:同步状态
现在可以了,但是提升BookForm/的地位,我感觉不太对。BookApp/在用户点击Save之前不关心对图书的任何修改,那么为什么需要保持其自身状态呢?
在codesandbox中尝试
现在可以了,但是提升BookForm/的地位,我感觉不太对。BookApp/在用户点击Save之前不关心对图书的任何修改,那么为什么需要保持其自身状态呢?
//.
classBookFormextendsComponent{
状态={.this . props . book };
组件将接收道具(下一个道具){
constnextBook=nextProps.book
if(this.props.book!==nextBook){
this.setState({.nextBook });
}
}
render(){
if(!this . props . book)return null;
返回(
lt。formgt。
h3Book/h3
lt。labelgt
标题:
lt。投入
value={this.state.title}
onChange={e=gt。this . SetState({ title : e . target . value })}
/gt。
lt。/label gt;
lt。labelgt
Author:
lt。投入
value={this.state.author}
onChange={e=gt。this . SetState({ author : e . target . value })}
/gt。
lt。/label gt;
lt。buttonOnClick={()=gt;this.props.onSave({.this . state })} gt;
救援
lt。/buttongt。
lt。/formgt。
);
}
}
//.
在codesandbox中尝试
这种方法通常被认为是一种糟糕的做法,因为它违背了React关于事实来源单一的想法。我不确定情况是否如此,但是同步状态并不总是容易的。此外,我尽量避免使用生命周期方法。
方法3:由Key控制的组件
但是为什么要回收旧状态呢?每次用户选择一本书,有一个新状态的新实例有意义吗?
为此,我们需要告诉React停止使用旧实例并创建一个新实例。这就是keyprop的作用。
//.
classBookAppextendsComponent{
状态={
书:本,
activeIndex:-1
};
render(){
const{books,activeIndex }=this.state
const active book=books[active index];
返回(
差异
lt。书单
书籍={books}
onEdit={index=gt。
this.setState({
活动索引:索引
})}
/gt。
lt。BookForm
key={activeIndex}
book={activeBook}
onSave={book=gt。
this.setState({
books:Object.assign([.books],{[activeIndex]:book}),
activeIndex:-1
})}
/gt。
/div
);
}
}
//.
在代码沙盒里试试。
如果某个元素具有与先前渲染不同的关键点,则“反应”会为其创建一个新实例。因此,当用户选择一本新书时,BookForm/的键发生变化,组件的新实例将被创建,状态将从props初始化。
本文转载自中文网站
25
2022-09
16
2022-09
15
2022-09
15
2022-09
15
2022-09
15
2022-09