Here, i have included a my example code. If it is one dimensional array means, i can easily insert json data's into my code. How to achieve this one with multidimensional json data with react js?
var Category = React.createClass({
render: function() {
return (
<div>
{this.props.data.map(function(el,i) {
return <div key={i}>
<div>
{el.product}
</div>
<div>
{el.quantity}
</div>
</div>;
})}
</div>
);
}
});
var data = [
{
product:"a",
quantity:28,
sub:[
{
subItem:'a'
},
{
subItem:'b'
}
]
},
{
product:"b",
quantity:20,
sub:[
{
subItem:'a'
},
{
subItem:'b'
}
]
}
];
React.render(<Category data={data}/>, document.body);
You can create component for sub categories like this,
var SubCategory = React.createClass({
render: function () {
var list = this.props.data.map(function(el, i) {
return <li key={i}>{ el.subItem }</li>;
});
return <ul>{ list }</ul>;
}
});
and use it in Category component
{this.props.data.map(function(el,i) {
return <div key={i}>
<div>{el.product}</div>
<div>{el.quantity}</div>
<SubCategory data={ el.sub } />
</div>;
})}
Example
Related
I thought this would be a simple task, but I've been working on this all day but still can't seem to figure it out.
I am receiving a very large (multiple layers of objects) JSON file which I stored in a state of my component, now I need to render that data on the screen. This has become difficult, because within the object I have several others objects which also may contain other objects.
So far, I am using Object.keys(myJSONObject).map(...) to try to get it done, however I can't seem to find a way to reach all the 'sub-objects'. Here is my current code:
render: function(){
return (
<div>
{
Object.keys(_this.state.content).map(function (key) {
if (typeof _this.state.content[key] instanceof Object){
//go through all objects and sub-objects???
}
return <div > Key: {
key
}, Value: {
_this.state.content[key]
} </div>;
})
}
</div>
);
}
Edit: I should probably add that my object is _this.state.content
Edit 2: Here is an example of the object I am looking to iterate through. Keep in mind that is it a lot bigger than this.
{ "3.8": [ "Something something" ],
"3.2": [ { "Blabla": [ "More things I am saying", "Blablablabal", "Whatever" ] } ],
"2.9": [ { "Foo": [ "bar", "something something something something", "blablablabalbalbal" ] } ]}
Edit 3: Here is how I would somewhat like it to look when rendered:
3.8:
- Something something
3.2:
- Blabla:
- More things I am saying
- Blablablabal
- Whatever
2.9:
-Foo:
-bar
...
Is this what your are after: http://codepen.io/PiotrBerebecki/pen/PGjVxW
The solution relies on using React's reusable components. It accepts objects of varying levels of nesting as per your example. You can adjust it further to accommodate even more types of objects.
const stateObject = {
"3.8": [ "Something something" ],
"3.2": [ { "Blabla": [ "More things I am saying", "Blablablabal", "Whatever" ] } ],
"2.9": [ { "Foo": [ "bar", "something something something something", "blablablabalbalbal" ] } ]
}
class App extends React.Component {
render() {
const renderMainKeys = Object.keys(stateObject)
.map(mainKey => <MainKey mainKey={mainKey}
innerObject={stateObject[mainKey]} />);
return (
<div>
{renderMainKeys}
</div>
);
}
}
class MainKey extends React.Component {
render() {
if (typeof this.props.innerObject[0] === 'string') {
return (
<div>
<h4>{this.props.mainKey}</h4>
<ul>
<li>{this.props.innerObject[0]}</li>
</ul>
</div>
);
}
const innerObjectKey = Object.keys(this.props.innerObject[0])[0];
const innerList = this.props.innerObject[0][innerObjectKey];
return (
<div key={this.props.mainKey}>
<h4>{this.props.mainKey}</h4>
<InnerKey innerObjectKey={innerObjectKey} innerList={innerList}/>
</div>
)
}
}
class InnerKey extends React.Component {
render() {
return (
<ul>
<li>{this.props.innerObjectKey}</li>
<InnerList innerList={this.props.innerList} />
</ul>
)
}
}
class InnerList extends React.Component {
render() {
if (!Array.isArray(this.props.innerList)) {
return (
<ul>
<li>{this.props.innerList}</li>
</ul>
);
}
const listItems = this.props.innerList.map(function(item, index) {
return <li key={index}>{item}</li>;
});
return (
<ul>
{listItems}
</ul>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
Here is a code which I wrote sometime back to handle 3 layers of nesting in my json file.
JSON
var a = {
"parent":{
"name":"x",
"child":{
"name":"y",
"subchild":{
"name":"check"
}
}
}
}
Iterator
Object.keys(obj).map(function(key,index){
let section = obj[key]
//getting subsections for a single section
let subSections = section["subsections"] // get you nested object here
Object.keys(subSections).map(function(subSectionId,key){
//getting a single sub section
let subSection=subSections[subSectionId]
//getting instruments for a sub section
let nestedSection = subSection["//key"] //get you next nested object here
Object.keys(instruments).map(function(instrumentId,key){
//operation
}
})
})
})
})
Hope it helps.
I know how to run loops inside react but how do I do it inside an object which is already inside an array being looped?
I am trying to display each ingredient item as an <li>, so far I have got it working with recipe but I am lost with ingredient. If anyone could chime in, I'd appreciate it.
var Recipes = React.createClass({
// hook up data model
getInitialState: function() {
return {
recipeList: [
{recipe: 'Cookies', ingredients: ['Flour ', 'Chocolate']},
{recipe: 'Cake', ingredients: ['Flour ', 'Sprinkles']},
{recipe: 'Onion Pie', ingredients: ['Onion ', 'Pie-Crust']}
]
}
},
loop: function() {
{this.state.recipeList.flatMap('ingredients').map(item, index) => (
<li key={index} className="list-group-item">{ingredient.ingredients}</li>
)}
},
render: function() {
return (
<div>
{this.state.recipeList.map((item, index) => (
<div className="panel panel-default">
<div className="panel-heading"><h3 className="panel-title">{item.recipe}</h3></div>
<div className="panel-body">
<ul className="list-group">
{this.loop}
</ul>
</div>
</div>
)
)}
</div>
);
}
});
How about this way :
loop: function(ingredients) {
return ingredients.map((ingredient, index) => {
return (<li key={index} className="list-group-item">{ingredient}</li>)
})
},
render(){
...
{this.loop(item.ingredients)}
...
}
One more thing, you shouldn't use index of array as key because it will be difficult to manage when editting the array later. It will be better if you assign key with something very unique like id or index + Date.now()
You seem to be missing a return statement in the loop method.
You can cascade rendering as deep as you'd wish, only remember that you need to call the method instead of just placing it in the component structure (see this.loop without call parentheses in your sample):
var myComponent = React.createClass({
renderListElements: function (parent) {
return this.state.listElements[parent].map((element, index) => (
<li
className="my-component__sub-component__list-element"
key={`${parent.uid}_${element.uid}`}
>
{element.name}
</li>
));
},
render: function () {
var parentsId = [ 0, 1, 2, 3 ];
return (
<div className="my-component">
{parentsId.map((item, index) => (
<div
className="my-component__sub-component"
key={item.uid}
>
{this.renderListElements(item)}
</div>
)}
<div/>
);
}
});
I'm trying to test React out for myself. I got a simple "Hello World" message outputted successfully, so I tried taking this a step further and loop through data.
I'm getting a "waiting for roots to load…to reload the inspector” error, which after Googling tells me I have an issue with my syntax. I just can't find it... so your help is much appreciated!
var data = [
{perc:"2.2%", year:"5"},
{perc:"3.2%", year: "7"}
]
var Rates = React.createClass({
render: function(){
return (
<div>
<RateList data={this.props.rates} />
</div>
)
}
});
var Rate = React.createClass({
render: function(){
return (
<div>
<ul>
<li>{this.props.percent}</li>
</ul>
</div>
)
}
});
var RateList = React.createClass({
render: function(){
return (
<div>
<ul>
{ this.props.data.map(function(rate){
return <Rate percent={rate.perc} />
}) }
</ul>
</div>
)
}
});
ReactDOM.render(<Rates rates={data} />, document.getElementById("wow"));
It seems you could simplify a little.
var data = [
{perc:"2.2%", year:"5"},
{perc:"3.2%", year: "7"}
]
var RateList = React.createClass({
render: function(){
return (
<div>
<ul>
{ this.props.rates.map(function(rate){
return <li>{rate.perc}</li>
}) }
</ul>
</div>
)
}
});
ReactDOM.render(<RateList rates={data} />, document.getElementById("wow"));
I am facing a very similar problem to this question, but I am fetching data using a Promise and want to render it into the DOM when it comes through. The console.log() displays all the items correctly. I think my problem is that the lodash.map returns an array of <li> elements, and so I am trying to call this.renderItems() in order to render (but renderItems() doesn't seem to exist). Am I doing something unconventional, is there an easier way, is there an equivalent function to replace my renderItems()?
renderArticleHeadline: function(article) {
console.log('renderArticleHeadline', article.headline);
return (
<li>
{article.headline}
</li>
)
},
render: function() {
return (
<div>
<ul>
{
this.renderItems(
this.fetchFrontPageArticles().then(data => {
lodash.map(data, this.renderArticleHeadline)
})
)
}
</ul>
</div>
);
}
It should be something like this
getInitialState: function() {
return {
items: []
};
},
renderArticleHeadline: function(article) {
return (
<li>
{article.headline}
</li>
);
},
componentDidMount: function() {
this.fetchFrontPageArticles().then(data => {
this.setState({
items: data
});
});
},
render: function() {
var items = lodash.map(this.state.items, this.renderArticleHeadline);
return (
<div>
<ul>
{items}
</ul>
</div>
);
}
P.S. read thinking in react
I'm spending time on something probably simple:
I'd like to implement a search bar, ideally updating the list of item as-you-type. My small app uses React and Backbone (for models and collections).
Displaying the list isn't too hard, it all works perfectly doing this (the mixin i'm using basically allows easy collections retrieval):
var List = React.createClass ({
mixins: [Backbone.React.Component.mixin],
searchFilter: function () {
//some filtering code here, not sure how (filter method is only for arrays...)
}
}
getInitialState: function () {
initialState = this.getCollection().map(function(model) {
return {
id: model.cid,
name: model.get('name'),
description: model.get('description')
}
});
return {
init: initialState,
items : []
}
},
componentWillMount: function () {
this.setState({items: this.state.init})
},
render: function(){
var list = this.state.items.map(function(obj){
return (
<div key={obj.id}>
<h2>{obj.name}</h2>
<p>{obj.description}</p>
</div>
)
});
return (
<div className='list'>
{list}
</div>
)
}
});
Now i've tried with no success to first translate the backbone collection into "state" with the getInitialState method, my idea was to proxy through a copy of the collection, which then could hold the search results. I'm not showing here my attemps for the sake of clarity(edit: yes i am), could someone guide me to the right approach? Thanks in advance.
There are many ways to accomplish this, but the simplest (in my opinion) is to store your search criteria in the List component's state and use it to filter which items from your collection get displayed. You can use a Backbone collection's built in filter method to do this.
var List = React.createClass ({
mixins: [Backbone.React.Component.mixin],
getInitialState: function () {
return {
nameFilter: ''
};
},
updateSearch: function (event) {
this.setState({
nameFilter: event.target.value
});
},
filterItems: function (item) {
// if we have no filter, pass through
if (!this.state.nameFilter) return true;
return item.name.toLowerCase().indexOf(this.state.nameFilter) > -1;
},
render: function(){
var list = this.props.collection
.filter(this.filterItems.bind(this))
.map(function(obj){
return (
<div key={obj.id}>
<h2>{obj.name}</h2>
</div>
)
});
return (
<div className='list'>
{list}
<input onChange={this.updateSearch} type="text" value={this.state.nameFilter}/>
</div>
)
}
});
var collection = new Backbone.Collection([
{
name: 'Bob'
},
{
name: 'Bill'
},
{
name: 'James'
}
]);
React.render(<List collection={collection}/>, document.body);
jsbin
The search criteria could easily be passed down from a parent component as a prop, so the search input does not have to live inside your List component.
Eventually I also found a different solution (below), but it involves copying the entire collection into state, which is probably not such a good idea...
var List = React.createClass ({
mixins: [Backbone.React.Component.mixin],
searchFilter: function () {
var updatedlist = this.state.init;
var searchText = this.refs.searchbar.getDOMNode().value
updatedlist = updatedlist.filter(function (item) {
return item.name.toLowerCase().search(
searchText.toLowerCase()) !== -1
});
this.setState({items: updatedlist})
}
},
getInitialState: function () {
initialState = this.getCollection().map(function(model) {
return {
id: model.cid,
name: model.get('name'),
description: model.get('description')
}
});
return {
init: initialState,
items : []
}
},
componentWillMount: function () {
this.setState({items: this.state.init})
},
render: function(){
var list = this.state.items.map(function(obj){
return (
<div key={obj.id}>
<h2>{obj.name}</h2>
<p>{obj.description}</p>
</div>
)
});
return (
<div className='list'>
<input ref='searchbar' type="text" placeholder="Search" onChange={this.searchFilter}/>
{list}
</div>
)
}
});