18910140161

React中跨组件分发状态的三种方法介绍

顺晟科技

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初始化。

本文转载自中文网站

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航