Andy92
Andy92

Reputation: 141

Correct way to rerender my React component?

I'm pretty new to React (coming from Angular 1), and have been playing around with it somewhat. I have a test script that loops through a multidimensional object, and binds it to the dom.

I then add a new item to the object wrapped in a setTimeout. Is calling the ReactDOM.render below that the best way to rerender the React component?

var items = [
    { name: 'Matt', link: 'https://google.com' },
    { name: 'Adam', link: 'https://bing.com' },
    { name: 'Luke', link: 'https://yahoo.com' },
    { name: 'John', link: 'https://apple.com' }
];

var RepeatModule = React.createClass({
    getInitialState: function() {
        return { items: [] }
    },
    render: function() {

    var listItems = this.props.items.map(function(item) {
        return (
            <li key={item.name}>
                <a className='button' href={item.link}>{item.name}</a>
            </li>
        );
    });

    return (
        <div className='menu'>
            <h3>The List</h3>
            <ul>
                {listItems}
            </ul>
        </div>
    );
    }
});

ReactDOM.render(<RepeatModule items={items} />, document.getElementById('react-content'));

setTimeout(function() {
    var newline = { name: 'Added item', link: 'https://amazon.com' };
    items.push(newline);
    ReactDOM.render(<RepeatModule items={items} />, document.getElementById('react-content'));
}, 2000);

Much appreciated :)

Upvotes: 0

Views: 296

Answers (3)

farukg
farukg

Reputation: 523

You could use the react state

working demo: http://codepen.io/anon/pen/WGyamK

var RepeatModule = React.createClass({
    getInitialState: function() {
        return { items: [
            { name: 'Matt', link: 'https://google.com' },
            { name: 'Adam', link: 'https://bing.com' },
            { name: 'Luke', link: 'https://yahoo.com' },
            { name: 'John', link: 'https://apple.com' }
        ] }
    },
    componentDidMount() {
        var _this = this
        setTimeout(function() {
            var newline = { name: 'Added item', link: 'https://amazon.com' };
            _this.setState({items: _this.state.items.concat(newline)});
        }, 2000);

    },
    render: function() {

        var listItems = this.state.items.map(function(item) {
            return (
                <li key={item.name}>
                    <a className='button' href={item.link}>{item.name}</a>
                </li>
            );
        });

        return (
            <div className='menu'>
                <h3>The List</h3>
                <ul>
                    {listItems}
                </ul>
            </div>
        );
    }
});
ReactDOM.render(<RepeatModule />, document.getElementById('react-content'));

That being said, you should use some library trigerring the rerender for you. You are coming from Angular, so firstly you need to know that React is not a whole framework like angular, but just the "V in MVC".

I use react in combination with redux. Check out https://github.com/reactjs/redux for more.

There are some good boilerplate codes out there to get started quickly. I like this https://github.com/davezuko/react-redux-starter-kit

Hope you find this useful.

Upvotes: 0

Piotr Berebecki
Piotr Berebecki

Reputation: 7468

React docs advise to place async calls in the componentDidMount method.

Load Initial Data via AJAX
Fetch data in componentDidMount. When the response arrives, store the data in state, triggering a render to update your UI.
https://facebook.github.io/react/tips/initial-ajax.html

Here is a demo: http://codepen.io/PiotrBerebecki/pen/KgZGao

const App = React.createClass({
  getInitialState: function() {
    return {
      items: [
        { name: 'Matt', link: 'https://google.com' },
        { name: 'Adam', link: 'https://bing.com' },
        { name: 'Luke', link: 'https://yahoo.com' },
        { name: 'John', link: 'https://apple.com' }
      ]
    };
  },

  componentDidMount: function () {
    setTimeout(() => {
      this.setState({
        items: [
          ...this.state.items,
          { name: 'Added item', link: 'https://amazon.com' }
        ]
      });
    }, 2000);
  },

  render: function() {
    var listItems = this.state.items.map(function(item) {
          return (
              <RepeatModule key={item.name} href={item.link} itemName={item.name} />
          );
    });

    return (
      <div>
        <h3>The List</h3>
        {listItems}
      </div>
    );
  }
});


const RepeatModule = React.createClass({
    render: function() {
      return (
          <div className='menu'>
              <ul>
                <li>
                  <a className='button' href={this.props.href}>{this.props.itemName}</a>
                </li>
              </ul>
          </div>
      );
    }
});


ReactDOM.render(
  <App />,
  document.getElementById('app')
);

Upvotes: 1

vijayst
vijayst

Reputation: 21846

Wrap the RepeatModule within a parent component. Items should be part of the state. Have a button to add new item. On click of the new item, pass the item details to the parent component. The parent component should update the state.

Your code won't work because you are pushing item to items. You should slice it before pushing it. React checks for props / state change using the === operator.

setTimeout(function() {
    var newline = { name: 'Added item', link: 'https://amazon.com' };
    var newItems = items.slice();
    newItems.push(newline);
    ReactDOM.render(<RepeatModule items={newItems} />, document.getElementById('react-content'));
}, 2000);

Upvotes: 0

Related Questions