【问题标题】:Force re-render D3 component on React after state change in parent在父状态更改后强制在 React 上重新渲染 D3 组件
【发布时间】:2019-03-08 03:48:32
【问题描述】:

我有两个反应组件(在打字稿中)。在第一个组件中,我有一些菜单。

   <Menu.Item
      name="graph"
      active={activeItem === "graph"}
      onClick={this.handleItemClick}
    />
    <Menu.Item
      name="flow"
      active={activeItem === "flow"}
      onClick={this.handleItemClick}
    />

相应的事件处理程序

handleItemClick = (e, { name }) => {this.setState({ activeItem: name, hello: name, selection:name });};

在渲染函数中,我将此决定作为属性传递给另一个反应组件 D3Core

返回之前,

var child = this.state.selection==="graph"? true : false ;

内部返回,

<D3Core renderfull = {child} width={this.state.width} height={this.state.height} data={data} />

在 D3Core 渲染函数中,我使用以下内容来渲染图形

if(this.props.renderfull) {
        return <div style={style} ref={mountPoint => (this.ctrls.mountPoint = mountPoint)} />;
    } else {
        return <p>Hello</p>;
    }

在 componentDidMount 回调中完成强制布局 d3 计算。

componentDidMount() {
    const { width, height, data } = this.props;
    const force = d3
      .forceSimulation()
      .nodes(data.nodes)
      .force('charge', d3.forceManyBody().strength(-120))
      .force('link', d3.forceLink(data.links).distance(50))
      .force('center', d3.forceCenter(width / 2, height / 2));

const svg = d3
      .select(this.ctrls.mountPoint)
      .append('svg')
      .attr('width', width)
      .attr('height', height);
    ...

我面临的问题是,当我第一次加载文档时,它会显示图表,但如果我离开菜单并返回菜单,它只会加载 div 而不是图表。我想我必须重新渲染图表,但如何?

我猜这是因为所有组件都已渲染,而 d3 计算根本没有发生。我应该在渲染内部进行计算吗?

我附上了几张截图。第一个屏幕截图显示了第一次加载页面时呈现的图形。第二个屏幕截图显示,当我离开图形菜单并返回时,图形不仅呈现 div 元素。

编辑 1:Here 是我的 d3 代码

【问题讨论】:

  • div中还有SVG吗,隐藏组件时是否销毁SVG?
  • @rioV8 不,我不会破坏它。我在帖子中添加了我的代码。
  • var child = this.state.selection==="graph"; 就够了,表达式是布尔值

标签: javascript reactjs typescript d3.js


【解决方案1】:

我认为问题是当renderfull 被关闭并重新打开时,React 从文档中删除旧的div 并添加一个新的,并且您的 D3 实例仍然附加到旧的(已删除)分区。但是,D3Core 组件实例始终处于挂载状态,因此您不会收到新的 componentDidMount 回调。

最干净的解决方案是将 D3 内容移动到 D3Core 的子组件(例如,假设子组件名为 D3Sub)并让 D3Corerender 方法返回 &lt;D3Sub ...&gt;,仅当renderfull 是真的。然后,当renderfull 关闭并重新打开时,D3Sub 实例将被销毁并创建一个新的D3Sub 实例,并且新实例将获得一个componentDidMount 回调。

【讨论】:

  • 感谢这解决了这个问题。但是正如你所说的“React 从文档中删除旧的 div 并添加一个新的”不应该再次触发 componentDidMount 回调吗?
  • 给定D3Core 组件实例上的componentDidMount 回调仅在该实例完全初始化后调用一次。之后,该实例可能会重新渲染多次(导致添加和/或删除 DOM 元素和子组件),每次您将获得componentDidUpdate,而不是componentDidMount。原则上,您可以编写 componentDidUpdate 来检查 renderfull 是否从 false 变为 true,如果是,则初始化另一个 D3 实例,但使用子组件可以避免在 componentDidMountcomponentDidUpdate 之间重复代码。
  • 是否会在componentdidmount之前调用组件更新?
  • 组件的第一次渲染调用componentDidMount而不是componentDidUpdate;见this diagram。如果您的问题是关于父组件的componentDidUpdate 与父组件重新渲染时刚刚创建的子组件的componentDidMount 的顺序,我相信子组件的componentDidMount 首先出现,但是您可以试试看。
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
  • 2021-05-17
相关资源
最近更新 更多