为了账号安全,请及时绑定邮箱和手机立即绑定

ReactJS-提升状态与保持本地状态

ReactJS-提升状态与保持本地状态

慕容3067478 2019-10-21 10:42:41
在我公司,我们正在将Web应用程序的前端迁移到ReactJS。我们正在使用create-react-app(更新为v16),而没有Redux。现在,我停留在页面上,该页面可以通过以下图像简化:在componentDidMount()MainContainer方法中,使用相同的后端请求检索由三个组件(SearchableList,SelectableList和Map)显示的数据。然后,此请求的结果存储在MainContainer的状态中,其结构大致如下:state.allData = {  left: {    data: [ ... ]  },  right: {    data: [ ... ],    pins: [ ... ]  }}LeftContainer state.allData.left从MainContainer 接收作为道具,并props.left.data再次作为道具传递到SearchableList。RightContainer state.allData.right从MainContainer 接收作为道具,并传递props.right.data到SelectableList和props.right.pinsMap。SelectableList显示一个复选框,允许对其项目执行操作。每当对SelectableList组件的一项操作发生时,它可能会对Map引脚产生副作用。我决定在RightContainer状态下存储一个列表,该列表保留SelectableList显示的所有项目ID。此列表作为道具传递给SelectableList和Map。然后,我将一个回调传递给SelectableList,该回调使每当进行选择时都会更新RightContainer中的ID列表;新道具同时出现在SelectableList和Map中,因此render()在这两个组件中都被称为。它工作正常,有助于将Rightable容器中的SelectableList和Map可能发生的所有事情保留在RightContainer中,但是我想问这对于提升状态和事实真相的概念是否正确。作为可行的替代方案,我想到了向MainContainer中的_selected每个项目添加一个属性state.right.data,并将select回调三级传递给SelectableList,以处理MainContainer中的所有可能动作。但是,一旦发生选择事件,这最终将强制加载LeftContainer和RightContainer,从而引入了实现逻辑的需求,例如shouldComponentUpdate()避免无用的逻辑,render()尤其是在LeftContainer中。从体系结构和性能的角度来看,哪种是/可能是优化此页面的最佳解决方案?您可以在下面摘录我的组件,以帮助您了解情况。MainContainer.jsclass MainContainer extends React.Component {  constructor(props) {    super(props);    this.state = {      allData: {}    };  }  componentDidMount() {    fetch( ... )      .then((res) => {        this.setState({          allData: res        });      });  }  render() {    return (      <div className="main-container">        <LeftContainer left={state.allData.left} />        <RightContainer right={state.allData.right} />      </div>    );  }}export default MainContainer;RightContainer.jsclass RightContainer extends React.Component {  constructor(props) {    super(props);    this.state = {      selectedItems: [ ... ]    };  }  onDataSelection(e) {    const itemId = e.target.id;    // ... handle itemId and selectedItems ...  }
查看完整描述

3 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

如React文档所述


通常,几个组件需要反映相同的变化数据。我们建议将共享状态提升到最接近的共同祖先。


对于React应用程序中发生的任何数据更改,应该只有一个“事实来源”。通常,首先将状态添加到需要呈现的组件。然后,如果其他组件也需要它,则可以将其提升到最接近的共同祖先。与其尝试在不同组件之间同步状态,不如依靠自上而下的数据流。


与双向绑定方法相比,解除状态涉及编写更多的“样板”代码,但这样做的好处是,查找和隔离错误的工作量较小。由于任何状态都“存在”于某个组件中,并且仅该一个组件即可更改它,因此大大减少了错误的表面积。此外,您可以实现任何自定义逻辑来拒绝或转换用户输入。


因此,从本质上讲,您还需要将树状结构提升到正在被兄弟姐妹组件使用的状态。因此,您第selectedItems一个将状态存储为状态的实现RightContainer是完全合理的,并且是一种很好的方法,因为父级不需要了解信息,并且这data是由的两个child组件共享的,而这两个组件RightContainer现在只有一个来源真相。


根据您的问题:


作为可行的替代方案,我想到了将_selected属性添加到中的每个项目中state.right.data,MainContainer并将select回调向下传递到三个级别,以SelectableList处理in中的所有可能动作MainContainer


我不同意这是比第一种更好的方法,因为您MainContainer不需要知道selectedItems或处理程序的任何更新。MainContainer对这些州没有做任何事情,只是将其传承下去。


考虑到optimise on performance您自己谈论实现a的问题shouldComponentUpdate,但是可以通过扩展组件来避免这种情况,该组件通过扩展React.PureComponent本质上实现了and shouldComponentUpdate的shallow比较来实现。stateprops


根据文档:


如果您的React组件的render()函数在相同的道具和状态下呈现相同的结果,则React.PureComponen在某些情况下可以使用t来提高性能。


但是,如果多个深度嵌套的组件正在使用同一数据,则使用redux并将该数据存储在redux状态是有意义的。这样,整个应用程序就可以全局访问它,并且可以在不直接相关的组件之间共享它。


例如考虑以下情况


const App = () => {

    <Router>

         <Route path="/" component={Home}/>

         <Route path="/mypage" component={MyComp}/>

    </Router>

}

现在,如果Home和MyComp都想访问相同的数据。您可以通过通过renderprop 调用它们,将数据作为来自prop的prop 传递。但是,可以通过使用以下connect函数将这两个组件都连接到Redux状态来轻松实现


const mapStateToProps = (state) => {

   return {

      data: state.data

   }

}


export connect(mapStateToProps)(Home);

和类似的MyComp。易于配置操作以更新相关信息


同样,为您的应用程序配置Redux特别容易,您将能够在单个化简器中存储与相同内容相关的数据。这样,您还可以模块化您的应用程序数据


查看完整回答
反对 回复 2019-10-21
?
呼唤远方

TA贡献1856条经验 获得超11个赞

通过使用Redux,您可以避免此类回调并在单个存储中维护整个状态-因此,使您的父组件连接组件-并使左右组件哑巴-只需将您从父组件获得的道具传递给子组件-然后您在这种情况下,不必担心回调。


查看完整回答
反对 回复 2019-10-21
  • 3 回答
  • 0 关注
  • 721 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信