【问题标题】:React component that's rendered dynamically does not rerender on parent state changes动态呈现的 React 组件不会在父状态更改时重新呈现
【发布时间】:2021-09-01 16:45:09
【问题描述】:

我有一个组件,我想在渲染之前运行一个非反应动画库。这使我无法采用仅使用标准隐藏/显示逻辑的标准路线。我最初尝试使用 ReactDOM.createPortal 但根本没有渲染组件。使用 ReactDOM.render,我已经让元素在动画完成后正确渲染,并且我能够成功地将更改传播到“父”状态,但状态更改不会传播回“子”状态.这是我的代码:

HTML

    <div id="root"></div>
    <div id="childPlaceholder"></div>

Javascript

import './App.css';
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

function App() {
  const [data, updateData] = useState(0)
  function add(val) {
    console.log("add");
    updateData(val);
  }
  function renderSubpage() {


    let $el = document.getElementById("childPlaceholder");
    // NonReactAnimationLibrary.ShowContainer($el);
    ReactDOM.render(<Child number={data} add={add} />, $el);
    // ReactDOM.createPortal(<Child number={data} add={add} />, $el);

  }
  return ( <>
    <button onClick={renderSubpage}>
      add child
    </button>
    <div> data: {data}</div>
</>
  );
}
function Child(props) {
  return <>
  <button onClick={()=>{props.add(props.number + 1)}}>add number</button>
    <div>child {props.number}</div>
  </>
}

export default App;

是否可以在反应中做到这一点?

更新 1:

所以我更新了每个 Olivers 响应的代码,它使用门户正确呈现,但子组件仍然不会重新呈现父组件中的状态更改

const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");

function Child(args) {
  return ReactDOM.createPortal(<>
   <div>child:  {args.number}</div>
   <button onClick={()=>{args.add(args.number+1)}}>Increment base number</button>
  </>, childRoot);
}

export default class App extends React.Component {
  constructor() {
    super();
    this.state = { data: 0, number:0 };
  }
  
 
  add = (val)=> {
    this.setState({
      ...this.state,
      number: val
    });
  }
  addChild = () => {
    this.setState(prevState => ({data: prevState.data + 1}));
  }
  render() {
    const children = Array(this.state.data)
      .fill()
      .map((_, i) => <Child key={i} number={0} add={this.add}/>);
  
    return ( 
      <div>
        <button onClick={this.addChild}>
          add child
        </button>
        <div> data: {this.state.data}</div>
        {children}
      </div>
    );
  }
}

ReactDOM.render(<App/>, root);

更新 2:

找到了罪魁祸首。改变了

      number={0}

      number={this.state.number}

它可以工作

【问题讨论】:

  • 你是什么意思:“传播回“孩子”?
  • Child 组件中的 {props.number} 值不会更新,而 App 组件中的 {data} 值会更新
  • 这是ReactDOM.createPortal 的完美用例,我不明白为什么它不适合你,也许你没有正确使用它。
  • 唯一的区别是我用相同的参数调用了 ReactDOM.createPortal 而不是 ReactDOM.render。这是正确的使用方法吗?我在帖子中添加了我尝试使用它的方式
  • ReactDOM.createPortal 必须使用inisde渲染方法,可以看文档reactjs.org/docs/portals.html

标签: javascript reactjs


【解决方案1】:

React.createPortal必须在render方法内部使用(我使用了类组件,因为在SO示例中我不能使用钩子,你当然可以使用函数式组件)。

您可以在下面的App 组件或Child 组件中使用它:

const root = document.getElementById("root");
const childRoot = document.getElementById("childPlaceholder");

function Child({number}) {
  return <div>child {number}</div>;
}

class App extends React.Component {
  constructor() {
    super();
    this.state = { data: 0 };
  }
  
  addChild = () => {
    this.setState(prevState => ({data: prevState.data + 1}));
  }
  
  render() {
    const children = Array(this.state.data)
      .fill()
      .map((_, i) => <Child key={i} number={i} />);
  
    return ( 
      <div>
        <button onClick={this.addChild}>add child</button>
        <div> data: {this.state.data}</div>
        {ReactDOM.createPortal(children, childRoot)}
      </div>
    );
  }
}

ReactDOM.render(<App/>, root);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<div id="childPlaceholder"></div>

【讨论】:

  • 我能够让渲染部分正常工作,但是当我将 on click 函数重新增加父状态编号时,它仍然不会导致子组件重新渲染
  • 我已将更新后的代码添加到原始帖子中
  • 这显然是因为我很笨,并且我传入了 0 而不是父母状态下的 number 属性。非常感谢!!!
猜你喜欢
  • 2021-07-10
  • 2016-12-05
  • 2021-01-12
  • 2019-04-10
  • 2019-01-09
  • 1970-01-01
  • 2021-12-21
  • 2020-05-12
  • 1970-01-01
相关资源
最近更新 更多