Iterate on json in react component - javascript

I have this json in my react component as codeData
{
"type":"Simple count",
"codeCount": {
"lang": {
"java": 4,
"cpp":3,
"c":5
},
"ds": {
"array": 4,
"tree":5
}
}
}
In page I want to show above json in form of list as follows.
lang
*java(4)
*cpp(3)
*c(5)
ds
*array(4)
*tree(5)
For that I have to iterate through java object codeData.codeCount.But I am not able to figure out how to show key and value in loop.
class Showdata extends Component {
render() {
const {codeData} = this.props;
return (
<div>
for (let [key, value] of {codeData.codeCount}(myObj)) {
<ul>
</ul>
}
</div>
);
}

Check this:
let data = {
"type":"Simple count",
"codeCount": {
"lang": {
"java": 4,
"cpp":3,
"c":5
},
"ds": {
"array": 4,
"tree":5
}
}
}
class Showdata extends React.Component {
render() {
const {codeCount} = data;
return (
<div>
{Object.keys(codeCount).map(key=>{
return <ul>
{key}
{
Object.keys(codeCount[key]).map(el=> <li>{el} : {codeCount[key][el]}</li>)
}
</ul>
})}
</div>
);
}
}
ReactDOM.render(<Showdata/>, document.getElementById('app'))
<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='app'/>

Related

How to create algolia autocomplete custom renderer using react class component

I am tickling with Algolia autocomplete, and I am trying to replicate their custom renderer in react using the class component. This is the sandbox of the minimal demo of custom renderer using functional component,
and here is my attempt to convert it into a class component.
import { createAutocomplete } from "#algolia/autocomplete-core";
import { getAlgoliaResults } from "#algolia/autocomplete-preset-algolia";
import algoliasearch from "algoliasearch/lite";
import React from "react";
const searchClient = algoliasearch(
"latency",
"6be0576ff61c053d5f9a3225e2a90f76"
);
// let autocomplete;
class AutocompleteClass extends React.PureComponent {
constructor(props) {
super(props);
this.inputRef = React.createRef();
this.autocomplete = null;
this.state = {
autocompleteState: {},
};
}
componentDidMount() {
if (!this.inputRef.current) {
return undefined;
}
this.autocomplete = createAutocomplete({
onStateChange({ state }) {
// (2) Synchronize the Autocomplete state with the React state.
this.setState({ autocompleteState: state });
},
getSources() {
return [
{
sourceId: "products",
getItems({ query }) {
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: "instant_search",
query,
params: {
hitsPerPage: 5,
highlightPreTag: "<mark>",
highlightPostTag: "</mark>",
},
},
],
});
},
getItemUrl({ item }) {
return item.url;
},
},
];
},
});
}
render() {
const { autocompleteState } = this.state;
return (
<div className="aa-Autocomplete" {...this.autocomplete?.getRootProps({})}>
<form
className="aa-Form"
{...this.autocomplete?.getFormProps({
inputElement: this.inputRef.current,
})}
>
<div className="aa-InputWrapperPrefix">
<label
className="aa-Label"
{...this.autocomplete?.getLabelProps({})}
>
Search
</label>
</div>
<div className="aa-InputWrapper">
<input
className="aa-Input"
ref={this.inputRef}
{...this.autocomplete?.getInputProps({})}
/>componentDidUpdate()
</div>
</form>
<div className="aa-Panel" {...this.autocomplete?.getPanelProps({})}>
{autocompleteState.isOpen &&
autocompleteState.collections.map((collection, index) => {
const { source, items } = collection;
return (
<div key={`source-${index}`} className="aa-Source">
{items.length > 0 && (
<ul
className="aa-List"
{...this.autocomplete?.getListProps()}
>
{items.map((item) => (
<li
key={item.objectID}
className="aa-Item"
{...this.autocomplete?.getItemProps({
item,
source,
})}
>
{item.name}
</li>
))}
</ul>
)}
</div>
);
})}
</div>
</div>
);
}
}
export default AutocompleteClass;
and the sandbox of the same version, I also tried using componentDidUpdate() but no luck, any lead where I did wrong would be much appreciated thank you :)
Ok, dont know why you need it made into class component but here you go:
import { createAutocomplete } from "#algolia/autocomplete-core";
import { getAlgoliaResults } from "#algolia/autocomplete-preset-algolia";
import algoliasearch from "algoliasearch/lite";
import React from "react";
const searchClient = algoliasearch(
"latency",
"6be0576ff61c053d5f9a3225e2a90f76"
);
// let autocomplete;
class AutocompleteClass extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
autocompleteState: {},
query: '',
};
this.autocomplete = createAutocomplete({
onStateChange: this.onChange,
getSources() {
return [
{
sourceId: "products",
getItems({ query }) {
console.log('getting query', query)
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: "instant_search",
query,
params: {
hitsPerPage: 5,
highlightPreTag: "<mark>",
highlightPostTag: "</mark>"
}
}
]
});
},
getItemUrl({ item }) {
return item.url;
}
}
];
}
});
}
onChange = ({ state }) => {
console.log(state)
this.setState({ autocompleteState: state, query: state.query });
}
render() {
const { autocompleteState } = this.state;
return (
<div className="aa-Autocomplete" {...this.autocomplete?.getRootProps({})}>
<form
className="aa-Form"
{...this.autocomplete?.getFormProps({
inputElement: this.state.query
})}
>
<div className="aa-InputWrapperPrefix">
<label
className="aa-Label"
{...this.autocomplete?.getLabelProps({})}
>
Search
</label>
</div>
<div className="aa-InputWrapper">
<input
className="aa-Input"
value={this.state.query}
{...this.autocomplete?.getInputProps({})}
/>
</div>
</form>
<div className="aa-Panel" {...this.autocomplete?.getPanelProps({})}>
{autocompleteState.isOpen &&
autocompleteState.collections.map((collection, index) => {
const { source, items } = collection;
return (
<div key={`source-${index}`} className="aa-Source">
{items.length > 0 && (
<ul
className="aa-List"
{...this.autocomplete?.getListProps()}
>
{items.map((item) => (
<li
key={item.objectID}
className="aa-Item"
{...this.autocomplete?.getItemProps({
item,
source
})}
>
{item.name}
</li>
))}
</ul>
)}
</div>
);
})}
</div>
</div>
);
}
}
export default AutocompleteClass;
Anyway the componentDidMount is called only once, and because of ref object is undefined it just returned from it.
Also messing with this in class components is quite a bad idea (that is why func components are recommended)

React map over the array object

I'm quite new with react stuff, what I am trying is to generate some dynamic stuff using .map()
This is my component:
import React, { Component } from "react";
class DynamicStuff extends Component {
state = {
options: [
{ id: 1, optionOne: "OptionOne" },
{ id: 2, optionTwo: "OptionTwo" },
{ id: 3, optionThree: "OptionThree" }
]
};
render() {
const options = [...this.state.options];
return (
<>
{options.map((option) => {
return {option}
})}
<span>{options.optionOne}</span>
<span>{options.optionTwo}</span>
<span>{options.optionThree}</span>
</>
);
}
}
export default DynamicStuff;
What I am doing wrong here and why the map is not generating expected result ?
Is it ok?
import React, { Component } from "react";
class DynamicStuff extends Component {
state = {
options: [
{ id: 1, value: "OptionOne" },
{ id: 2, value: "OptionTwo" },
{ id: 3, value: "OptionThree" }
]
};
render() {
const options = [...this.state.options];
return (
<>
{options.map((option) => {
return <span>{option.value}</span>
})}
</>
);
}
}
export default DynamicStuff;
You have made your options object incorrectly. We need to have a same attribute over all the objects in the array.
class App extends React.Component {
state = {
options: [
{ id: 1, option: "OptionOne" },
{ id: 2, option: "OptionTwo" },
{ id: 3, option: "OptionThree" }
]
};
render() {
const options = [...this.state.options];
return (
<>
{options.map((option, index) => (
<li key={index}>{option.option}</li>
))}
</>
);
}
}
Another thing, If you need to map an array. You don't need to have many spans. Having a one is just enough. The map function will iterate and give you all the things.
The map used here is actually to convert the js object into a react element, but your usage here is still a js object after the map conversion. The react element may be a <p key = {option.id}> {option. optionOne} </p>.
If there is a react element after the return in your map, it is correct.
{options.map((option) => {
return <p key = {option.id}> {option. optionOne} </p>
})}
or
{options.map((option) => <p key = {option.id}> {option. optionOne} </p>)}
YOu need to map and return the HTML element
return ({
options.map((option) => {
return `<span key={option.id}>${option. option}</span>`
})
});
You should do something like
render() {
const { options } = this.state;
return (
<div className="option-wrapper">
{options.length > 0 && options.map(option => {
return <span key={option.id}>{option.option}</span>
})}
</div>
);
}

ReactJS / Javascript - Trouble Rendering Components for Items in Object

I'm having some trouble rendering components for each instance of an item in an object.
While I'm able to log the individual titles of each item, the return function doesn't return anything, regardless of which component I try to return. There are no errors, apparently.
Is there perhaps a better way of returning components according to each item in an object?
Any help would be greatly appreciated! :)
import React, { Component } from 'react';
export default class Wrapper extends Component {
const obj = () => ({
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
});
renderSingleItem(instance) {
console.log(instance); // THIS WORKS JUST FINE!
return ( // THIS DOESN'T WORK?!
<h2 key={instance.title}>
{instance.description}
</h2>
);
}
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
render() {
return (
<div>
{this.renderAllItems(this.obj)}
</div>
);
}
}
<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>
I've also attempted the following method, which actually renders a component, but only for the first item in the object.
import React, { Component } from 'react';
export default class Wrapper extends Component {
const obj = () => ({
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
});
renderSingleItem(instance) {
console.log(instance);
return (
<h2 key={instance.title}>
{instance.description}
</h2>
);
}
renderAllItems(data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
var instance = data[key];
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
return (this.renderSingleItem(instance));
}
}
}
}
}
render() {
return (
<div>
{this.renderAllItems(this.obj)}
</div>
);
}
}
<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>
FYI, in my project, I'm importing a JSON object.
You have 2 issues in this function.
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
You need to add another return before Object.keys and you should be using .map and not .forEach since forEach is void, meaning it wont return anything.
The code should look like this.
renderAllItems(data) {
return Object.entries(data).map(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
This solution worked great for me:
import React from 'react';
import { render } from 'react-dom';
export default class Wrapper extends React.Component {
constructor(props) {
super(props)
this.obj = {
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
};
}
renderSingleItem(instance, k) {
console.log(instance); // THIS WORKS JUST FINE!
return (<h2 key={k} children={instance.description} />);
}
/*
* Not necessary
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}*/
render() {
return (
<div>
{Object.keys(this.obj).map((k) => {
return this.renderSingleItem(this.obj[k], k);
})}
</div>
);
}
}
// I'll leave this for you
// render(<Wrapper />, document.getElementById('root'));

es2015 map doesn't support array of object?

Created a jsbin to demo the error, you can see the error here https://jsbin.com/muhuxunome/1/edit
class Hello extends React.Component {
render() {
const normalizedStats = [
{
"name": "Confirmed",
"count": 7
},
{
"name": "Unprocessed",
"count": 2
},
{
"name": "Not Suitable",
"count": 9
},
{
"name": "Shortlisted",
"count": 17
}
];
return(
<div>
normalizedStats.map(obj =>
<li>{obj.name} ({obj.count})</li>
)
</div>
)
}
}
I got error of obj is not defined? I tried lodash's map it worked, not sure why map of es2015 has error here.
You forgot the "{}"
return (
<div>
{normalizedStats.map((obj, index) => {
return <li key={index}>{obj.name} ({obj.count})</li>;
})}
</div>
);
You need to use curly braces whenever you want to do JavaScript interpolation in your JSX.
Change
normalizedStats.map(obj =>
<li>{obj.name} ({obj.count})</li>
)
to
{normalizedStats.map(obj =>
<li>{obj.name} ({obj.count})</li>
)}
Wrap the map result within {}. You need to do that in order to render your elements within JSX. Also ideally should be adding a key to the retuned JSX elements from map
{normalizedStats.map(obj =>
<li key={obj.name}>{obj.name} ({obj.count})</li>
)}
Code with sorting
class Image extends React.Component {
render(){
return <img className="center" {...this.props} />;
}
}
Image.propTypes = {
src: React.PropTypes.string.isRequired
};
class Hello extends React.Component {
render() {
const normalizedStats = [
{
"name": "Confirmed",
"count": 7
},
{
"name": "Unprocessed",
"count": 2
},
{
"name": "Not Suitable",
"count": 9
},
{
"name": "Shortlisted",
"count": 17
}
];
normalizedStats.sort(function(a, b) {return a.count - b.count})
return(
<div>
{normalizedStats.map((obj) => {
return <li key={obj.name}>{obj.name} ({obj.count})</li>
}
)}
</div>
)
}
}
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
name: 'JSBin'
};
}
render() {
return (<div className="app">
<Hello />
</div>);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
JSBIN

Rendering a nested navigation in React

I have the following data structure for my website’s navigation. This is just a JSON object:
[{
"path": "/",
"name": "Home"
}, {
"path": "/products",
"name": "Products",
"subnav": [{
"path": "/sharing-economy",
"name": "Sharing Economy"
}, {
"path": "/pre-employment-screening",
"name": "Pre-Employment Screening"
}, {
"path": "/kyc-and-aml",
"name": "KYC & AML"
}]
}, {
"path": "/checks",
"name": "Checks"
}, {
"path": "/company",
"name": "Company"
}]
What I’d like to do is to render the following from it, having a nested list inside of the Products list item when the subnav key is present:
<ul>
<li>Home</li>
<li>Products
<ul>
<li>Sharing Economy</li>
<li>Pre-Employment Screening</li>
<li>KYC & AML</li>
</ul>
</li>
<li>Checks</li>
<li>Company</li>
</ul>
Currently, my React code looks like this:
// This is the data structure from above
import navigation from '../data/navigation.json'
const SubNavigation = (props) => {
// Here I’m trying to return if the props are not present
if(!props.subnav) return
props.items.map((item, index) => {
return <Link key={index} to={item.path}>{item.name}</Link>
})
}
class Header extends React.Component {
render() {
return (
<header className='header'>
{navigation.map((item, index) => {
return(
<li key={index}>
<Link to={item.path}>{item.name}</Link>
<SubNavigation items={item.subnav}/>
</li>
)
})}
</header>
)
}
}
export default Header
I’m using a functional stateless component to render the SubNavigation, however am running into trouble when item.subnav is undefined.
How would I adapt this code so that I conditionally render the SubNavigation based on the item.subnav key being present/undefined.
Could you try this:
<header className='header'>
{navigation.map((item, index) => {
return(
<li key={index}>
<Link to={item.path}>{item.name}</Link>
{ item.subnav && <SubNavigation items={item.subnav}/> }
</li>
)
})}
</header>
Change your code to:
const SubNavigation = (props) => {
// Here I’m trying to return if the props are not present
if(!props.items) return null;
return (<ul>
{props.items.map((item, index) => {
return <Link key={index} to={item.path}>{item.name}</Link>
})}
</ul>
);
}
Try the following:
import _ from 'underscore';
class Link extends React.Component
{
static defaultProps = {
to: '/hello'
};
static propTypes = {
to: React.PropTypes.string
};
render() {
var props = _.omit(this.props, 'to');
return (
<a href={this.props.to} {... this.props} />
);
}
}
class Header extends React.Component
{
static defaultProps = {
nav: [{"path":"/","name":"Home"},{"path":"/products","name":"Products","subnav":[{"path":"/sharing-economy","name":"Sharing Economy"},{"path":"/pre-employment-screening","name":"Pre-Employment Screening"},{"path":"/kyc-and-aml","name":"KYC & AML"}]},{"path":"/checks","name":"Checks"},{"path":"/company","name":"Company"}]
};
static propTypes = {
nav: React.PropTypes.array
};
render() {
var props = _.omit(this.props, 'nav');
return (
<header className="header" {... props}>
{this.renderNav(this.props.nav)}
</header>
)
}
renderNav(items, props = {}) {
return (
<ul {... props}>
{items.map((v, k) => this.renderNavItem(v, {key: k}))}
</ul>
);
}
renderNavItem(item, props = {}) {
return (
<li {... props}>
<Link to={item.path}>
{item.name}
</Link>
{item.subnav ? this.renderNav(item.subnav) : null}
</li>
);
}
}

Categories

Resources