Reputation: 793
I'm having this use case where there is a 'load more' button on the page to fetch more items from an API endpoint, and so I want these items to get appended to the DOM when they arrive. The thing is that the HTML page that is served by the web server comes with some extra list items (as seen below) within the same item-list
div container I mount my React component, with empty data/props, on page load.
<div class="item-list">
<div class="item-list__child-item"></div>
<div class="item-list__child-item"></div>
...
<div class="item-list__child-item"></div>
</div>
My assumption is that if I handle this in the ReactJS way, as soon as I fetch more items from the server (REST) and append those items to an 'itemList' state array, react will somehow replace all of the content that holds that 'item-list' div where the component was mounted on.
A quick workaround that I'm thinking would work and that it doesn't rely on the isomorphic stuff and pre-rendering the react component on the server, is to create a separate sibling div having the same div class name 'item-list' and adding an id attribute to mount the component on, so the resulting HTML would go like:
<div class="item-list">
<div class="item-list__child-item"></div>
<div class="item-list__child-item"></div>
...
<div class="item-list__child-item"></div>
</div>
<div class="item-list" id="react-component-name"></div>
Maybe there is a cleaner way to do it without getting into the isomorphic stuff, or maybe I'm not understanding the React concept and how it works. Anyways will appreciate any directions you may have on this.
Upvotes: 7
Views: 33884
Reputation: 363
Check this simple fiddle demo:
var Page = React.createClass({
getInitialState : function(){
return{
items : ["one","two","three"]
}
},
addClick : function(){
this.state.items.push("more");
this.forceUpdate();
},
render : function(){
return <div>{this.state.items.map(function(item){return <div className="bla-bla-class">{item}</div>})}<br/><div onClick={this.addClick}>ADD</div></div>;
}
});
React.render(<Page />, document.body);
Upvotes: 1
Reputation: 4755
OK, your question wasn't clear on this, but the data that is represented by what was generated in the HTML will be entirely different from the data that you will be getting via AJAX.
There's a simple solution to this. Instead of creating an entirely new DOM element that will be adjacent to your original DOM layout, what you will do is grab the data that was already there, store it into an array, and append the new data that you will grab via AJAX into that Array. This way, you will reap the benefit of React's DOM diffing. Why is it useful? Maybe you want to let the user sort the data, or interact with the data directly, while it will remain in full control of a parent React component.
So anyways, take a look at this fiddle: https://jsfiddle.net/x4jjry04/3/. It's based on Paul Booblic's fiddle.
var Page = React.createClass({
getDefaultProps: function () {
return {
items: []
}
},
getInitialState : function(){
return{
items : this.props.items
}
},
componentDidMount: function () {
// Mimics an AJAX call, but replace this with an actial AJAX call.
setTimeout(function () {
var dataFromAjax = ['one', 'two', 'three'];
this.setState({
items: this.state.items.concat(dataFromAjax)
});
}.bind(this));
},
addClick : function(){
this.state.items.push("more");
this.forceUpdate();
},
render : function(){
return <div>{this.state.items.map(function(item){return <div className="bla-bla-class">{item}</div>})}<br/><div onClick={this.addClick}>ADD</div></div>;
}
});
var elements = document.querySelectorAll('.item-list__child-item');
var initialvalues = Array.prototype.slice
.call(elements)
.map(function (div) {
return div.innerHTML;
});
React.render(<Page items={initialvalues} />, document.body);
Upvotes: 6
Reputation: 849
I assume you are using react serverside to render the list?
On page load you fetch the original list from the server and have the component "re-render" the elements. re-render is in quotes, because React wont actually update the list unless the list changes. Now you are setup with a component that works as expected, and you can add elements to the list as you want.
The general Idea with isomorphic/universal React is that you treat your app as a normal Single Page App, and let React handle the magic of dirty checking.
This also means that you can use the same component when rendering on the server, since your component doesn't contain any client specific code.
Upvotes: 0