手机版

详细解释在React中跨组件分布状态的三种方法

时间:2021-08-30 来源:互联网 编辑:宝哥软件园 浏览:

当我第一百次问自己时,我正在研究一个典型的CRUD屏幕:“我应该保持这个组件中的状态还是将其移动到父组件中?”。

如果需要稍微控制一下子组件的状态。你可能遇到了同样的问题。

让我们用一个简单的例子和三种修复方法来回顾一下。前两种方法是常见的做法,而第三种方法不是很常规。

问题;

为了向您展示我的意思,我将使用一个简单的书籍CRUD屏幕(如此简单,它没有创建和删除操作)。

我们有三个组成部分。BookList/是一个组件,它显示书籍列表和编辑书籍的按钮。book form/有两个输入和一个按钮来保存对图书的更改。和BookApp/,它包含另外两个组件。

那么,我们的地位如何?好吧,BookApp/应该跟踪图书列表,识别当前正在编辑的图书内容。book list/没有状态。并且BookForm/应该将输入保持在当前状态,直到单击保存按钮。

从“反应”导入反应{组件};从“react-dom”导入{ render };const books=[ { title:《永恒的终结》,作者:《艾萨克阿西莫夫》},//.];const BookList=({ books,Onedit })=(table tr thBook Title/th th thanctions/th/tr { books . map((book,index)=(tr TD { book . Title }/TD TD button OnClick={()=Onedit(index)} Edit/button/TD/tr))}/table);类BookForm扩展了组件{ state={.this . props . book };render() { if(!this.props.book)返回null返回(表单h3Book/h3标签Title:输入值={ this . state . title } onChange={ e=this . setstate({ title : e . target . value })}//标签标签Author:输入值={ this . state . author } onChange={ e=this . setstate({ author : e . target . value })}//标签按钮onClick={()=this . props onsave({ 0。this.state })}保存/按钮/表单);}}class BookApp扩展了Component { state={ books : books,active index :-1 };render() { const { books,activeIndex }=this.stateconst active book=books[active index];return(div BookList books={ books } onEdit={ index=this . setstate({ active index : index })}/BookForm book={ active book } onSave={ book=this . setstate({ books : object . assign([.books],{ [activeIndex]: book }),active index :-1 })}//div);}}render(BookApp /,document . getelementbyid(' root ');看起来不错,但没用。

BookForm/state是在我们创建组件实例时初始化的,所以当从列表中选择另一本书时,父对象不能让它知道它需要更改它。

我们怎么才能修好它?

方法1:受控组件

一种常见的方法是提升状态并将BookForm/转换为受控组件。我们删除BookForm/state,将activeBook添加到BookApp/state,并向BookForm/添加一个onChange prop,每次输入时都会调用它。

//.BookForm类扩展了组件{ render() { if(!这个.道具.书)返回空返回(表单h3Book/h3标签标题:输入值={这个。道具。书。title } onChange={ e=this。道具。onChange({ 0.this.props.book,书名: e . target。value })}//标签标签Author:输入值={这个。道具。书。作者} onChange={ e=this。道具。onChange({ 0.this.props.book,作者: e . target。value })}//标签按钮onClick={()=this。道具。onsave()}保存/按钮/表单);} }类BookApp扩展了组件{状态={ books : books,activeBook: null,活动索引:-1 };render() { const { books,activeBook,active index }=this . state return(div BookList books={ books } onEdit={ index=this。setstate({活动图书: }.books[index] },active index : index })}/BookForm book={ active book } onChange={ book=this。setstate({ active book : book })} OnSave={()=this。setstate({ books : object。分配([.books],{ [activeIndex]: activeBook }),activeBook: null,active index :-1 })}//div);}}//.现在它可以工作,但对我来说,提升BookForm /的状态感觉不对。在用户单击"保存"之前,BookApp /不关心对书的任何更改,那么为什么需要将其保持在自己的状态?

方法2:同步状态

现在它可以工作,但对我来说,提升BookForm /的状态感觉不对。在用户单击"保存"之前,BookApp /不关心对书的任何更改,那么为什么需要将其保持在自己的状态?

//.类BookForm扩展了组件{ state={.这个。道具。book };组件将接收道具(下一个道具){ const next book=下一个道具。书;if (this.props.book!==NextBook){这个。SetState({ 0.nextBook });} } render() { if(!这个.道具.书)返回空返回(表单h3Book/h3标签标题:输入值={这个。国家。title } onChange={ e=this。setstate({ title : e . target。value })}//标签标签Author:输入值={这个。国家。作者} onChange={ e=this。setstate({ author : e . target。value })}//标签按钮onClick={()=this。道具保存({ 0 .this.state })}保存/按钮/表单);}}//.这种方法通常被认为是一种不好的做法,因为它违背了反应关于拥有单一事实来源的想法。我不确定是这种情况,然而,同步状态并不总是那么容易。此外,我尽量避免使用生命周期方法。

方法3:由钥匙控制的组件

但为什么我们要回收旧的状态呢?每次用户选择一本书时,拥有一个全新状态的新实例是不是有意义?

为此,我们需要告诉反应停止使用旧实例并创建一个新实例。这就是关键道具的用途。

//.class BookApp扩展组件{状态={ books : books,活动索引:-1 };render() { const { books,active index }=this . state const active book=books[active index];return(div BookList books={ books } onEdit={ index=this。setstate({活动索引: index })}/BookForm键={活动索引} book={活动book } onSave={ book=this。setstate({ books : object。分配([.books],{ [activeIndex]: book }),active index :-1 })}//div);}}//.如果元素具有与上一个渲染不同的键,则反应会为其创建一个新实例。因此,当用户选择新书时,BookForm /的键更改,将创建组件的新实例,并从小道具初始化状态。

有什么收获?重用组件实例意味着更少的数字正射影像图突变,这意味着更好的性能。因此,当我们强制反应创建组件的新实例时,我们会为额外的数字正射影像图突变获得一些开销。但是对于这样的情况,这种开销是最小的,其中密钥没有变化太快而且组件不大。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:详细解释在React中跨组件分布状态的三种方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。