【问题标题】:Child component props not reflecting state change from parent子组件道具不反映父组件的状态更改
【发布时间】:2019-11-26 14:18:21
【问题描述】:

我的应用程序部分使用了 4 个组件,1 个父组件和 3 个子组件。正如预期的那样,父组件处理所有状态并通过 props 将值传递给子组件。

父组件包含更新状态更改的方法,也通过 props 传递。子组件除了组件方法外没有状态,它们仅使用 props 来存储可视数据。

我遇到的问题是,当我调用更新父状态的方法时,父状态已成功更新(通过控制台验证),但是通过其道具反映此状态的子组件没有直观地呈现状态变化。

代码如下,我会尽力解释:

父组件更新状态方法:

handleUpvoteState(blurtIndex) {
    let blurts = [...this.state.followingBlurts],
        updatedBlurt = {...blurts[blurtIndex]};
    updatedBlurt.vote++;
    blurts[blurtIndex] = updatedBlurt;
    this.setState({
        followingBlurts: blurts
    });
    console.log(this.state.followingBlurts[blurtIndex].vote); // State change reflected.
}

父组件将状态传递给子道具:

<LazyBlurtsPanel
     appendDate={this.state.appendDate}
     random={this.state.randomize} 
     blurts={this.state.followingBlurts} 
     handleLazyState={this.handleLazyState}
     handleUpvoteState={this.handleUpvoteState}
     lazyElement='lzyfollowing'
     apiMethod={this.state.apiMethod}
     currentUser={false}
 />

惰性面板组件(上图)然后通过 props 将数据发送到 footer child:

<BlurtFooter 
   voteCount={this.props.blurts[i].vote}
   currentUser={this.props.currentUser}
   blurtId={this.props.blurts[i]._id}
   blurtIndex={i}
   handleUpvoteState={this.props.handleUpvoteState}
 />

当我打电话时

this.props.handleUpvoteState(index)

在我的子页脚组件中,父状态已成功更新。但是,页脚组件不会重新渲染以反映父级的更新状态。

这是未重新渲染的页脚组件代码:

render() {
    return (
        <div className="blurt-panel-footer">
           <UpvoteCount voteCount={this.props.voteCount}/>

非常感谢任何帮助。

编辑:关于如何调用 blurtfooter 存在一些混淆,因此我将有关如何在 LazyBlurtPanel 组件内的循环内构建面板的代码包括在内。这是代码:

for(let i=numRendered; i<renderCount; i++) {
  if (this.props.blurts[i]) {
    renderBlurts.push(
         <div className='blurt-panel' id={(((i + 1) % 6) === 0) ? this.props.lazyElement : 'false'} key={i}>
              <BlurtHeader blurt={this.props.blurts[i]} />
              <div className='blurt-panel-body'>
                  <Sanitizer dirty={ this.props.blurts[i].text } />
                  {
                      (this.props.blurts[i].blurtImg !== 'false')? <img src={'/images/blurt/' + this.props.blurts[i].blurtImg} /> : ''
                  }
              </div>
              <BlurtFooter 
                  voteCount={this.props.blurts[i].vote}
                  currentUser={this.props.currentUser}
                  blurtId={this.props.blurts[i]._id}
                  blurtIndex={i}
                  handleUpvoteState={this.props.handleUpvoteState}
                  key={this.props.blurts[i]._id} //Tried with and without key here..
              />
          </div>
      );
  }
}

【问题讨论】:

  • let blurts = JSON.parse(JSON.stringify(this.state.followingBlurts)); 试试这个。
  • @sk01 我的初始状态将 followingBlurts 设置为一个数组...为什么要切换到对象表示法?正如我的问题中提到的,状态实际上更新没有问题。不过谢谢!
  • 状态改变是异步的。如果它工作正常,则状态更改不应反映在控制台中。这里的问题是当您使用扩展运算符时,数组引用是相同的。因此,您正在直接更改该数组。 Json stringify 会解决这个问题。
  • @sk01 我的描述有点误导。状态更改反映在控制台中,但它总是落后一个数字(由于您提到的异步行为,顺便说一句,良好的观察),但我可以验证它在第二次按下按钮后更新状态(upvote)。而且我只直接对数组进行更改,这是状态数组的浅拷贝......只是为了方便而尝试了你的解决方案,我的朋友不走运。
  • 尝试在LazyBlurtsPanelrender() 方法中添加console.log,以查看状态更改后是否正在重新渲染。如果我是对的,您正在循环渲染BlurtFooter,那么您应该会看到有关缺少关键属性的警告。不确定是否会导致此问题,但请尝试添加key={this.props.blurts[i]._id}

标签: javascript reactjs


【解决方案1】:

尝试更改BlurtFooter 的调用方式。即使这不能解决问题,它仍然是更易于维护的代码

render() {
  const { currentUser, blurts, lazyElement, handleUpvoteState } = this.props;
  return (
    <Fragment>
      {
        blurts.filter(x => x).map((blurt, index) => (
          <div className="blurt-panel" id={(((index + 1) % 6) === 0) ? lazyElement : 'false'} key={blurt._id}>
              <BlurtHeader blurt={blurt} />
              <div className="blurt-panel-body">
                  <Sanitizer dirty={blurt.text} />
                  {
                      blurt.blurtImg !== 'false' &&
                      <img src={`/images/blurt/${blurt.blurtImg}`} />
                  }
              </div>
              <BlurtFooter 
                  voteCount={blurt.vote}
                  currentUser={currentUser}
                  blurtId={blurt._id}
                  blurtIndex={index}
                  handleUpvoteState={handleUpvoteState}
              />
          </div>
        )
      }
    </Fragment>
  );
}

还有很多其他的改进可以做,但看看它是如何工作的,尤其是正确设置key 是必须的。

我不确定div 上的id 是什么,但它看起来也很可疑,不应该在那里。

另外,blurts.filter(x =&gt; x) 部分也不需要,所以应该改进状态以不需要它

更新:确保采用上面的最新代码

【讨论】:

  • 这间接地帮助我解决了我的问题,本质上是通过迫使我仔细查看我的lazyloader。我在之前的版本中使用了状态,并且我没有完全删除导致某种奇怪状态冲突的代码。老实说,我认为我实际上 under 使事情复杂化,因为我的lazyloader 中发生了很多事情。您的改进似乎都是有效的,除了我使用带有循环的数组 var(与 .map 相比)的原因是因为我需要在用户滚动时动态地向数组添加更多项目。非常感谢你在这里帮助了我。
【解决方案2】:

状态应该始终以非变异的方式更新。这种方式反应核心库可以理解数据发生了变化。 数组和对象在内存中使用引用指针。因此,即使我们更新这些引用类型变量中的值,它也不会影响这些变量的原始内存位置。 因此,在内存中创建一个新变量并复制您需要更新的状态,然后使用新变量设置状态。这样我们就可以避免这个问题。 您还可以使用现代 es6 + 方法创建非变异结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-03
    • 2021-01-28
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    相关资源
    最近更新 更多