title: React + d3 force graph doesn't update position of last added node
body: <p>I have a React component that lets me add nodes to a d3 force graph. Whenever I add a node its position in the underlying data is updated by the simulation, but its position is not updated visually until the next node is added. Is anybody able to spot why?</p>
  
  <p>I've made a stripped back example that demonstrates the issue, which can also be seen <a href="https://codesandbox.io/s/kx99609k7v" rel="nofollow noreferrer">in this codesandbox</a>:</p>
  
  <pre><code>import React from "react";
  import shortid from "shortid";
  import * as d3 from "d3";
  
  const WIDTH = 500;
  const HEIGHT = 500;
  
  class Graph extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        nodes: [],
        value: shortid(),
      };
    }
  
    handleChange = event =&gt; {
      this.setState({ value: event.target.value });
    };
  
    handleAddNode = event =&gt; {
      event.preventDefault();
  
      const newNodes = [...this.state.nodes, { id: this.state.value }];
  
      this.setState({ nodes: newNodes, value: shortid() });
    };
  
    componentDidMount() {
      this.initialise(this.state.nodes);
      this.draw(this.state.nodes);
    }
  
    componentDidUpdate() {
      this.draw(this.state.nodes);
    }
  
    initialise = nodes =&gt; {
      const container = d3
        .select(this.svg)
        .attr("width", WIDTH)
        .attr("height", HEIGHT)
        .append("g")
        .attr("class", "container")
        .attr("transform", "translate(" + WIDTH / 2 + "," + HEIGHT / 2 + ")");
  
      container.append("g").attr("class", "nodes");
  
      this.simulation = d3
        .forceSimulation(nodes)
        .alphaDecay(0.2)
        .force("charge", d3.forceManyBody())
        .force("collide", d3.forceCollide().strength(1))
        .on("tick", this.ticked);
    };
  
    draw = nodes =&gt; {
      this.nodesSelection = d3
        .select(".nodes")
        .selectAll(".node")
        .data(nodes);
  
      this.nodesSelection
        .enter()
        .append("circle")
        .attr("class", "node")
        .attr("data-id", d =&gt; d.id)
        .style("fill", "red")
        .attr("r", 5);
  
      this.simulation.nodes(nodes);
      this.simulation.alpha(1).restart();
  
      console.log(nodes);
    };
  
    ticked = () =&gt; {
      this.nodesSelection.attr("cx", d =&gt; d.x).attr("cy", d =&gt; d.y);
    };
  
    render() {
      return (
        &lt;div className="c-graph-container"&gt;
          &lt;form className="c-node-creator"&gt;
            &lt;div&gt;
              &lt;input
                type="text"
                value={this.state.value}
                onChange={this.handleChange}
              /&gt;
            &lt;/div&gt;
            &lt;button onClick={this.handleAddNode}&gt;Add&lt;/button&gt;
          &lt;/form&gt;
          &lt;svg ref={svg =&gt; (this.svg = svg)} className=".c-graph" /&gt;
        &lt;/div&gt;
      );
    }
  }
  
  export default Graph;
  </code></pre>