How to get Keys and values of a JSON object in React.js
What you need here is recursion.
Though, there is something missing in your design, you are not defining the exact condition for when should the program actually extract the value.
For example, lets define that if a value
of a given key
is a string, then we will render it to the page.
Such condition will look something like this:
if (typeof data[key] === 'string' || data[key] instanceof String)
Then with this decision, you can write a function that will take a data object and recursively will go over the object's keys, based on the condition above, it will return the value
Or another call to the same function with the value
as the new data object.
The function will look something along this block of code:
function generateData(data) {
const newData = Object.keys(data).reduce((result, currentKey) => {
if (typeof data[currentKey] === 'string' || data[currentKey] instanceof String) {
result.push(currentKey);
} else {
const nested = generateData(data[currentKey]);
result.push(...nested);
}
return result;
}, []);
return newData;
}
I'm using .reduce
here to build a new array. and as mentioned above, i will push to the new array either the key
or the result of a recursive call to the function with the value
as the new data object, of course based on the condition mentioned above.
Note, that the recursive call will return an array, so i'm using the spread syntax to extract it's members.
Now, we want our key
and value
to get rendered to the DOM
.
So instead to just push the key
or value
, we can push an element.
Here is a full running example:
const myData = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": {
"k1": "val1",
"k2": {
"p1": "v1",
"p2": "v2",
"p3": "v3"
}
}
}
const generateElement = (key,value) => {
return (
<div key={key} className="row">
<div className="col-xs-6 ins-label">{key}</div>
<div className="col-xs-6">{value}</div>
</div>
);
}
function generateData(data) {
const newData = Object.keys(data).reduce((result, currentKey) => {
if (typeof data[currentKey] === 'string' || data[currentKey] instanceof String) {
const elementToPush = generateElement(currentKey, data[currentKey]);
result.push(elementToPush);
} else {
const nested = generateData(data[currentKey]);
result.push(...nested);
}
return result;
}, []);
return newData;
}
class App extends React.Component {
render() {
const { data } = this.props;
return (
<div>
{generateData(data)}
</div>
)
}
}
ReactDOM.render(<App data={myData} />, document.getElementById('root'));
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
user2138675
Updated on October 06, 2020Comments
-
user2138675 over 3 years
I am new to react and trying to implement all the key and values of a JSON object in my web page. I have a below JSON structure. I want all the keys and values to be printed in my web page where key should be printed as labels.
{ "key1": "value1", "key2": "value2", "key3": "value3", "key4":{ "k1": "val1", "k2": { "p1": "v1", "p2": "v2", "p3": "v3" } } }
I have written the below code to get the keys and values of this JSON.
getValues() { let arr = []; arr = Object.keys(this.props.myArr).map(key => <div key={this.props.data[key]} className="row"> <div className="col-xs-6">{key}</div> <div className="col-xs-6">{this.props.myArr[key]} </div> </div> ) return arr; } render() { return ( <div> <Header /> <div className="content"> {this.getValues()} </div> </div> ) }
}
props.myArr has the entire object.
I am able to print the keys and values but not the nested object under key4(p1,p2,p3). I want all the keys along with its values to be printed one after another in my web page. Can someone tell me where am i going wrong and how to access all the keys (as labels) and values of the JSON object.
Edited-
const myObj = { "key1": "value1", "key2": "value2", "key3": "value3", "key4": { "k1": "val1", "k2": { "p1": "v1", "p2": "v2", "p3": "v3" } } } class Details extends React.component{ constructor(){ this.getValues = this.getValues.bind(this); } getValues() { let arr = []; arr = Object.keys(myObj).map(key => <div key={myObj[key]} className="row"> <div className="col-xs-6">{key}</div> <div className="col-xs-6">{myObj[key]} </div> </div> ) return arr; } generateData(myObj) { const newData = Object.keys(myObj).reduce((result, currentKey) => { if (typeof myObj[currentKey] === 'string' || myObj[currentKey] instanceof String) { const elementToPush = getValues(currentKey, myObj[currentKey]); result.push(elementToPush); } else { const nested = generateData(myObj[currentKey]); result.push(...nested); } return result; }, []); return newData; } render() { return ( <div> <Header /> <div className="content"> {this.generateData(myObj)} </div> </div> ) } }
}
P.S I am using getValues with map function to retrieve first level of key and values as the provided syntax by you under generateElement() gives me error.
-
user2138675 over 6 yearsThanks for providing the solution.Let me try this.So we do not need map function and Object.keys anymore?
-
Sagiv b.g over 6 yearsI'm using
Object.keys
ingenerateData
. And i went with.reduce
instead of.map
. -
user2138675 over 6 yearsJust curious to know if the above code you provided will work with any level of object nesting data and will print the keys and values regardless of the level of nesting the JSON would have.
-
Sagiv b.g over 6 yearsYes, as long as you keep this shape of object. i mean, a
key
can be either aString
or anObject
. note that we are not checking forArray
in our condition. -
user2138675 over 6 yearsYou are passing data inside generateElement () which should be the variable i assume which has the entire data so I am passing my entire object which is this.props.myArr or myData inside generateElement function but that is giving me error says its not defined.
-
Sagiv b.g over 6 yearsyou need to pass it to
generateData
, andgenerateData
will callgenerateElement
with the relevantkey
,value
pair. -
user2138675 over 6 yearsyeah same.typo that was.I am passing 'myData' into generateData() but that gives me error says its not defined. Also, i am not able to use the given syntax for generateElement().It gives me syntax error at =(key,value). Should i use Object.maps?
-
Sagiv b.g over 6 years
myData
is just a variable i used in the example. make sure you pass a valid defined object. as for the syntax error you get, it maybe due to the reason i'm using arrow functions (which i saw you are using as well by the way). maybe post an update to your question with the new syntax (don't delete the old syntax from the question just add another edit section) -
user2138675 over 6 yearsI have updated my changes above. The error i get now is getValues() is not defined.
-
Sagiv b.g over 6 yearsyou forgot to call it with
this
->this.getValues()
, you will also need tobind
generateData
in the constructor -
user2138675 over 6 yearsthis.getValues = this.getValues.bind(this) is not correct?
-
Sagiv b.g over 6 yearswhen you call it:
this.getValues(currentKey, myObj[currentKey])
-
user2138675 over 6 yearsThat works but now I see error as Objects are not valid as a React child (found: object with keys {k1, k2}). If you meant to render a collection of children, use an array instead.
-
user2138675 over 6 yearsThis is the response i am getting from backend so cant really change the format.
-
Sagiv b.g over 6 yearsif you want to use my example (which is fully working and running as you can see) that just copy paste the code. you are using half of what i wrote, so obviously you will get errors.
-
user2138675 over 6 yearsI was facing issue because of something else.Finally its working.Thanks a ton :)
-
user2138675 over 6 yearsHelp much appreciated.I would mark this as completed now.