jameslaneconkling / yard3

Yet Another React-D3 Integration Library
https://jameslaneconkling.github.io/yard3/
2 stars 3 forks source link

explore handling all rendering w/ React #13

Open jameslaneconkling opened 7 years ago

jameslaneconkling commented 7 years ago

e.g.

this:

export default class ScatterPlot extends React.Component {
  componentDidMount() {
    this.update();
  }

  componentDidUpdate() {
    this.update();
  }

  update() {
    const { data, x, y, containerWidth, containerHeight, yScale, xScale } = this.props;
    const $chart = d3.select(this.$chart);

    xScale.rangeRound([0, containerWidth]);
    yScale.rangeRound([containerHeight, 0]);

    const update = $chart.selectAll('.bar')
      .data(data);
    const enter = update.enter();
    const exit = update.exit();

    enter
      .append('circle')
      .attr('class', 'dot')
    .merge(update)
      .attr('r', 3.5)
      .attr('cx', d => xScale(x(d)))
      .attr('cy', d => yScale(y(d)));

    exit
      .remove();
  }

  render() {
    const { containerHeight, containerWidth, children } = this.props;

    return (
      <g
        ref={el => this.$chart = el}
      >
        { React.Children.map(children, child => React.cloneElement(child, {containerWidth, containerHeight})) }
      </g>
    );
  }
}

vs

const ScatterPlot = ({ data, xScale, yScale, x, y, containerHeight, containerWidth, children }) => {
    xScale.rangeRound([0, containerWidth]);
    yScale.rangeRound([containerHeight, 0]);

    return (
      <g
        ref={el => this.$chart = el}
      >
        {data.map(d => (
          <circle
            key={x(d)}
            className='dot'
            r='3.5'
            cx={xScale(x(d))}
            cy={yScale(y(d))}
          />
        ))}
        { React.Children.map(children, child => React.cloneElement(child, {containerWidth, containerHeight})) }
      </g>
    );
  }
jameslaneconkling commented 7 years ago

would this make transitions harder to implement? Would have to be handled by React, rather than by d3 alone... possibly using react-motion.

jameslaneconkling commented 7 years ago

Also, events should match the d3 callback, meaning pass data, index, and optionally the event object. The only way to match that functionality would be to create <D3Rect /> and <D3Circle /> (or just Rect/Circle?) components and do something like:

const BarChart = props => {
    const { containerHeight, containerWidth, children, data, xScale, yScale, x, y } = props;

    xScale.rangeRound([0, containerWidth]);
    yScale.rangeRound([containerHeight, 0]);

    const styles = extractStyles(props);
    const events = extractEvents(props);

    return (
      <g>
        { React.Children.map(children, child => React.cloneElement(child, {containerWidth, containerHeight})) }
        {data.map((d, i) => (
          <Rect
            key={x(d)}
            className='bar'
            width={xScale.bandwidth()}
            height={containerHeight - yScale(y(d))}
            x={xScale(x(d))}
            y={yScale(y(d))}
            data={d}
            index={i}
            {...styles}
            {...events}
          />
        ))}
      </g>
    );
}

and have Rect pass all properties on to a child <rect /> element, holding on to data and index, and adding each as an argument to any event fired on <rect />.