在React中,如何在render()运行之前将元素放到DOM上?

时间:2018-08-07 17:13:25

标签: javascript reactjs

我正在使用React(与Rails)并使用一个名为AnyChart的图表库。但是,我在渲染器中使用的AnyChart代码会自动寻找一个<div id="container"></div>元素以将图表附加到该元素上。如果我将图表代码与容器div一起放入渲染器中,则会出现错误,因为图表代码无法找到div,因为它尚未在DOM上。

我尝试使用Google搜索,但只发现了关于门户和裁判的内容,这些东西似乎不适用于我的问题。

我知道我可以将容器div移动到布局视图模板,但是我希望能够在图表下方的组件上呈现其他内容。这是我的整个StockContainer组件和InputField组件:

import React from 'react';
import InputField from '../components/InputField'

class StockContainer extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      stockTicker: ''
    }
    this.handleStockTickerChange = this.handleStockTickerChange.bind(this);
    this.handleClearForm = this.handleClearForm.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleClearForm(event){
    event.preventDefault();
    this.setState({
      stockTicker: ''
    });
  }

  handleStockTickerChange(event) {
    this.setState({stockTicker: event.target.value});
  }

  handleSubmit(event){
    event.preventDefault();

    let body = {
      symbol: this.state.stockTicker
    }
    console.log("Getting stock data for: " + body.symbol)
    this.handleClearForm(event);
  }

  componentDidMount() {
  }

  render() {

    var table, mapping, chart;

    table = anychart.data.table();
    table.addData([
    ['2015-12-25', 512.53, 514.88, 505.69, 507.34],
    ['2015-12-26', 511.83, 514.98, 505.59, 506.23],
    ['2015-12-27', 511.22, 515.30, 505.49, 506.47],

     ...sample data that will later be imported from an API
 
    ['2016-01-07', 510.93, 516.07, 506.00, 510.99],
    ['2016-01-08', 510.88, 515.93, 505.22, 509.95],
    ['2016-01-09', 509.12, 515.97, 505.15, 510.12],
    ['2016-01-10', 508.53, 516.13, 505.66, 510.42]
    ]);

    // mapping the data
    mapping = table.mapAs();
    mapping.addField('open', 1, 'first');
    mapping.addField('high', 2, 'max');
    mapping.addField('low', 3, 'min');
    mapping.addField('close', 4, 'last');
    mapping.addField('value', 4, 'last');

    // defining the chart type
    chart = anychart.stock();

    // set the series type
    chart.plot(0).ohlc(mapping).name('ACME Corp.');

    // setting the chart title
    chart.title('AnyStock Demo');

    // display the chart
    chart.container('container');
    chart.draw();

    return(
      <div>
        <h1>Research/Add a Stock</h1>
        <form onSubmit={this.handleSubmit}>
          <InputField
            label='Stock Symbol'
            name='ticker'
            content={this.state.stockTicker}
            handleChange={this.handleStockTickerChange}
          />
          <input type='submit' value='Get Info'/>
        </form>
        <div id="container"></div>
      </div>
    )
  }
}

export default StockContainer;

import React from 'react';

const InputField =(props) =>{
  return(
    <label>{props.label}
      <input
      type='text'
      name={props.name}
      value={props.content}
      onChange={props.handleChange}
      />
    </label>
  )
}
 export default InputField

3 个答案:

答案 0 :(得分:0)

就像上面评论中的Ishwor一样,您是否尝试过将chart.container()chart.draw()方法移动到组件的componentDidMount()挂钩中?

如果您可以为您的组件提供其余代码,我们也许可以提供帮助。

import React from 'react';
import InputField from '../components/InputField'

class StockContainer extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      stockTicker: ''
    }

    let table = anychart.data.table();
    table.addData([
    ['2015-12-25', 512.53, 514.88, 505.69, 507.34],
    ['2015-12-26', 511.83, 514.98, 505.59, 506.23],
    ['2015-12-27', 511.22, 515.30, 505.49, 506.47],

    ...sample data that will later be imported from an API
    ]);

    // mapping the data
    let mapping = table.mapAs();
    mapping.addField('open', 1, 'first');
    mapping.addField('high', 2, 'max');
    mapping.addField('low', 3, 'min');
    mapping.addField('close', 4, 'last');
    mapping.addField('value', 4, 'last');

    // defining the chart type
    let chart = anychart.stock();

    // set the series type
    chart.plot(0).ohlc(mapping).name('ACME Corp.');

    // setting the chart title
    chart.title('AnyStock Demo');

    // to be able to reference these later, if needed
    this.table = table;
    this.mapping = mapping;
    this.chart = chart;

    this.handleStockTickerChange = this.handleStockTickerChange.bind(this);
    this.handleClearForm = this.handleClearForm.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);

    // draw the chart
    this.drawMyAwesomeChart = this.drawMyAwesomeChart.bind(this);
  }

  componentDidMount() {
    this.chart.container('container');
    this.drawMyAwesomeChart()
  }

  componentDidUpdate() {
    // do some checks here to see if you need to draw chart?
    // this.drawMyAwesomeChart()
  }

  drawMyAwesomeChart() {
    this.chart.draw();
  }

}

然后,您可以绑定一个专门负责在股票报价变动时刷新图表的功能。我尚未对此进行全面测试,但是遵循这些思路的东西应该可以工作?

答案 1 :(得分:0)

尝试使用生命周期方法componentDidUpdate

答案 2 :(得分:0)

我知道它可以正常工作。这是我的代码:

import React from 'react';
import InputField from '../components/InputField'

const divStyle = {
  // width: '100%',
  // height: '100%'
};

class StockContainer extends React.Component {

  constructor(props){
    super(props)
    this.state = {
      stockTicker: '',
      currentPrices: [],
      show: false
    }
    this.handleStockTickerChange = this.handleStockTickerChange.bind(this);
    this.handleClearForm = this.handleClearForm.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.getDataForStockChart = this.getDataForStockChart.bind(this);
  }

  handleClearForm(event){
    // event.preventDefault();
    this.setState({ stockTicker: '' });
  }

  handleStockTickerChange(event) {
    this.setState({stockTicker: event.target.value});
  }

  getDataForStockChart(){
    let arrayOfArrays = []
    fetch(`https://api.iextrading.com/1.0/stock/${this.state.stockTicker}/chart/1y`)
    .then(response => {
      if (response.ok) {
        return response;
      } else {
        let errorMessage = `${response.status} (${response.statusText})`,
          error = new Error(errorMessage);
        throw(error);
      }
    })
    .then(response => response.json())
    .then(body => {
      body.forEach(obj => {
        arrayOfArrays.push([obj["date"], obj["open"], obj["high"], obj["low"], obj["close"]]);
      });
      this.setState({
        show: true,
        currentPrices: arrayOfArrays
      });
    })
    .catch(error => console.error(`Error in fetch: ${error.message}`));
  }

  componentDidUpdate(prevProps, prevState){
    var table, mapping, chart;

    if (this.state.currentPrices.length > 1 && this.state.show){
      this.refs.myInput.innerHTML = '';
      // node = this.myRef.current
      table = anychart.data.table();
      table.addData(this.state.currentPrices);

      mapping = table.mapAs();
      mapping.addField('open', 1, 'first');
      mapping.addField('high', 2, 'max');
      mapping.addField('low', 3, 'min');
      mapping.addField('close', 4, 'last');
      mapping.addField('value', 4, 'last');

      chart = anychart.stock();

      chart.plot(0).ohlc(mapping).name('Stock Chart');
      chart.title('AnyStock Demo');
      chart.container('container');
      chart.draw();
      this.setState({show: false})
      this.handleClearForm(event);
    }
  }
  // shouldComponentUpdate(nextProps, nextState){
  //   if (this.state.show)
  // }

  handleSubmit(event){
    event.preventDefault();
    this.getDataForStockChart();
    this.handleClearForm();
  }

  render() {
    return(
      <div>
        <h1>Research/Add a Stock</h1>
        <form onSubmit={this.handleSubmit}>
          <InputField
            label='Stock Symbol'
            name='ticker'
            content={this.state.stockTicker}
            handleChange={this.handleStockTickerChange}
          />
          <input type='submit' value='Get Info'/>
        </form>
        <div id="container" ref="myInput" style={divStyle}></div>
      </div>
    )
  }
}

export default StockContainer;