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
Related
I am in need of updating deeply nested object in a React state from a recursively rendered component. The items look like this and can be nested dynamically:
const items = [
{
id: "1",
name: "Item 1",
isChecked: true,
children: []
},
{
id: "3",
name: "Item 3",
isChecked: false,
children: [
{
id: "3.1",
name: "Child 1",
isChecked: false,
children: [
{
id: "3.1.1",
name: "Grandchild 1",
isChecked: true,
children: []
},
{
id: "3.1.2",
name: "Grandchild 2",
isChecked: true,
children: []
}
]
},
{
id: "3.2",
name: "Child 2",
isChecked: false,
children: []
}
]
}
]
I have a problem figuring out how to update the top level state from within a deeply nested component, because it only "knows" about itself, not the entire data structure.
class App extends React.Component {
state = {
items
};
recursivelyRenderItems(items) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<input type="checkbox" checked={item.isChecked} onChange={(event) => {
// TODO: Update the item's checked status
}} />
{this.recursivelyRenderItems(item.children)}
</li>
))}
</ul>
)
}
render() {
return (
<div>
{this.recursivelyRenderItems(this.state.items)}
</div>
);
}
}
How can I achieve this, please?
This works in your fiddle you posted.
Basically, each component needs to know about its item.isChecked and its parent's isChecked. So, create a component that takes 2 props, item and parentChecked where the latter is a boolean from the parent and the former becomes an mutable state variable in the constructor.
Then, the component simply updates its checked state in the event handler and it all flows down in the render method:
import React from "react";
import { render } from "react-dom";
import items from "./items";
class LiComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
item: props.item
}
}
render() {
var t = this;
return (
<ul>
<li key={t.state.item.id}>
{t.state.item.name}
<input
type="checkbox"
checked={t.state.item.isChecked || t.props.parentChecked}
onChange={event => {
t.setState({item: {...t.state.item, isChecked: !t.state.item.isChecked}})
}}
/>
</li>
{t.state.item.children.map(item => (
<LiComponent item={item} parentChecked={t.state.item.isChecked}/>
))}
</ul>
);
}
}
class App extends React.Component {
state = {
items
};
render() {
return (
<div>
{this.state.items.map(item => (
<LiComponent item={item} parentChecked={false} />
))}
</div>
);
}
}
render(<App />, document.getElementById("root"));
https://codesandbox.io/s/treelist-component-ywebq
How about this:
Create an updateState function that takes two args: id and newState. Since your ids already tell you what item you are updating: 3, 3.1, 3.1.1, you can from any of the recursive items call your update function with the id of the item you want to modify. Split the id by dots and go throw your items recursively to find out the right one.
For example from the recursive rendered item 3.1.1, can call updateState like this: updateState('3.1.1', newState).
import React from "react";
import { render } from "react-dom";
import items from "./items";
class App extends React.Component {
state = {
items
};
updateState = item => {
const idArray = item.id.split(".");
const { items } = this.state;
const findItem = (index, children) => {
const id = idArray.slice(0, index).join(".");
const foundItem = children.find(item => item.id === id);
if (index === idArray.length) {
foundItem.isChecked = !item.isChecked;
this.setState(items);
return;
} else {
findItem(index + 1, foundItem.children);
}
};
findItem(1, items);
};
recursivelyRenderItems(items) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<input
type="checkbox"
checked={item.isChecked}
onChange={event => this.updateState(item)}
/>
{this.recursivelyRenderItems(item.children)}
</li>
))}
</ul>
);
}
render() {
return <div>{this.recursivelyRenderItems(this.state.items)}</div>;
}
}
render(<App />, document.getElementById("root"));
Working example.
import React, { Component } from 'react';
import axios from 'axios';
class Meetups extends Component {
constructor(props) {
super(props);
console.log('in constructor');
this.state = {
results: [],
};
}
componentDidMount() {
console.log('meetup feed');
axios.get('https://api.meetup.com/2/categories?offset=0&format=json&photo-host=public&page=20&order=shortname&desc=false&sig_id=211627025&sig=ae69aec13f23c7837cd55c5a68b99e00719fa225')
//response
.then(response => response.json())
.then(data => this.setState({results:data.results}));
}
render() {
const {results} =this.state;
return(
<div>
{results.map(result =>
<div key={result.id} className='container'>
{result.name}
</div>
)}
</div>
);
}
}
export default Meetups;
JSON format which I'm receiving:
{
"results": [
{
"name": "Arts & Culture",
"sort_name": "Arts & Culture",
"id": 1,
"shortname": "Arts"
},
{
"name": "Book Clubs",
"sort_name": "Book Clubs",
"id": 18,
"shortname": "Book Clubs"
},
{
"name": "Career & Business",
"sort_name": "Career & Business",
"id": 2,
"shortname": "Business"
}
]
}
I am trying to use Meetup API in my project. But could not able to connect with it. There might be a problem with mapping. I want to know exact mapping for the given json format. Please help me out. Thanks
import React, { Component } from 'react';
import axios from 'axios';
class Meetups extends Component {
state = {
results: []
}
componentDidMount() {
axios.get('https://api.meetup.com/2/categories?offset=0&format=json&photo-host=public&page=20&order=shortname&desc=false&sig_id=211627025&sig=ae69aec13f23c7837cd55c5a68b99e00719fa225')
.then(response => {
let results = response.data.results;
this.setState({ results: results });
console.log(response);
})
}
render() {
let studentsDisplay = (
this.state.results.map( (result, index) =>
<div key={index} className="card" style= { {width: '18rem'} }>
{result.name}
<br/>
{result.shortname}
</div>
));
return (
<div className='container'>
{
studentsDisplay
}
</div>
);
}
}
export default Meetups;
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'));
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'/>
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>
);
}
}