反应父组件不重新渲染

Posted

技术标签:

【中文标题】反应父组件不重新渲染【英文标题】:React Parent Component not re-rendering 【发布时间】:2018-09-19 03:10:01 【问题描述】:

我有一个父组件,它呈现从 API 中提取的子列表(功能正确)。每个孩子都可以选择删除自己。当孩子删除自己时,我无法让父母重新渲染。我在这里阅读了与该主题相关的大约 50 个答案,并尝试了所有这些答案,但似乎没有任何效果。我错过了一些东西并卡住了。

组件已经连接了 redux,但我已经尝试了连接和不连接 redux 的代码。我也在回调中尝试了 this.forceUpdate() ,它也不起作用(我在下面的示例代码中将其注释掉了)。

class Parent extends React.Component 
  constructor(props) 
    super(props)
    this.refresh = this.refresh.bind(this)
    this.state = 
      refresh: false,
    
  

  componentDidMount()
    this.getChildren()
  

  refresh = () => 
    console.log("State: ", this.state)
    this.setState( refresh: !this.state.refresh )
    // this.forceUpdate();
    console.log("new state: ", this.state)
  

  getChildren = () => 
    axios.get(
      config.api_url + `/api/children?page=$this.state.page`,
      headers: token: ls('token')
      ).then(resp => 
         this.setState(
           children: this.state.children.concat(resp.data.children)
           )
         )
    

  render()
    return (

        <div>
             _.map(this.state.children, (chidlren,i) =>
                <Children
                  key=i
                  children=children
                  refresh=() => this.refresh()
                />
              )
         </div>
    )
  

然后在我的 Children 组件中,它工作得很好,并且删除按钮成功地从数据库中删除了记录,我有以下摘录:

  deleteChild = (e) => 
    e.preventDefault();
    axios.delete(
      config.api_url + `/api/children/$this.state.child.id`,
      headers: token: ls('token')
    ).then(resp => 
      console.log("The response is: ", resp);
    )
    this.props.refresh();
    

render() 
   return(
      <button class="btn" onClick=this.deleteChild>Delete</button>
  )

我确定我遗漏了一些简单或基本的东西,但我找不到。

【问题讨论】:

我应该补充一点,父组件状态确实发生了变化(即使第一个 console.log 没有反映它的异步性质,它正在改变,因为我在 Parent 中添加了一个按钮测试它),即使父状态发生变化,我删除的孩子也没有消失/父母没有重新渲染。 您可能希望将this.props.refresh(); 移动到axios 调用的then 处理程序中。 【参考方案1】:

您的父渲染方法仅取决于 this.state.children,它在您的删除事件中没有改变。将子 ID 传递给您的 this.props.refresh 方法,例如 this.props.refresh(this.state.child.id) 并在刷新方法中更新 this.state.children 或在删除后再次调用 get children 方法发生了

子进程中删除方法的代码

this.props.refresh(this.state.child.id)

父刷新方法代码

refresh = (childIdToBeDeleted) => 
    console.log("State: ", this.state)
    this.setState( refresh: !this.state.refresh )
    // this.forceUpdate();
    console.log("new state: ", this.state)

    //New code
    this.setState(children: this.state.children.filter(child => child.id !== childIdToBeDeleted);
  

【讨论】:

谢谢 - 这就像一个魅力(我将删除函数从子函数移到父函数作为回调,使用 id 作为参数,然后按照你的建议过滤状态)。现在代码也变得更好、更简洁了!【参考方案2】:

关于代码的一些注释。首先从 db 中删除然后重新加载可能会很慢并且不是最佳解决方案。或许可以考虑添加remove() 函数,该函数可以传递给子组件以更快地更新状态。 其次,如果你想调用setState,这取决于之前的状态,最好使用这样的回调方法(但我认为你需要其他东西见下文)

this.setState((prevState,prevProps) => 
   children: prevState.children.concat(resp.data.children))  

最后,我认为问题是什么。你实际上并没有从refresh 方法调用getChildren,所以状态没有更新,如果你想从数据库重新加载整个状态,你不应该连接,而是像这样设置它

.then(resp => 
  this.setState(children: resp.data.children)

希望对你有帮助。

编辑: 正如 cmets 中提到的,孩子们对refresh 的调用应该是承诺then

【讨论】:

谢谢 - 去看看。顺便说一句,chidlren 只是我的 *** 代码中的一个错字 - 真正的代码没有这个

以上是关于反应父组件不重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

防止子级在更新父级状态时重新渲染,使用父级方法作为本机反应的道具

反应我必须重新渲染父母才能重新渲染孩子吗?

反应父母对孩子道具传递而不重新渲染

使用 Lodash.remove 通过 Vuex 突变更改状态不会触发我的 Vue 组件中的反应式重新渲染

等待反应上下文后组件不重新渲染

在 useQuery 后反应组件不重新渲染