I can not show elements of my json - React - javascript

I need to retrieve all the information from other fields, not just "Padre" and "Hijo" in the json. I also want to get information from fields like "Id" or "url". I think I can not get them back for the reduced function in componentWillMount, what if I need for "Padre" and "Hijo".
This is an example of my json.
{
"Id": "114",
"Description": "SALUD NORMAL",
"Padre": "CRM",
"Hijo": "Argumentarios",
"URL": "www.test.com",
"Closable": "1",
"Autoload": "0",
"Visible": "1"
}
Nav would be the parent element and content his child, Menu. Menu is the one that creates a button for each of the "Padre" (this.props.menu) and "Hijo" (this.props.submenu) of the json.
This is my code.
class Nav extends Component{
constructor(props){
super(props)
this.state = {
menuSubmenu:[],
abrirSubmenu: false,
}
this.submenuClick = this.submenuClick.bind(this);
}
submenuClick() {
this.setState(state => ({
abrirSubmenu: !state.abrirSubmenu
}));
//alert('Click!')
}
componentWillMount(){
fetch('fake.php')
.then(response => response.json())
.then(menuSubmenu =>{
const PadreMap = menuSubmenu.reduce((acc, obj) => {
if (!acc[obj.Padre]) {
acc[obj.Padre] = {
...obj,
Hijo: [obj.Hijo],
Description: [obj.Description]
};
} else {
!acc[obj.Padre].Hijo.includes(obj.Hijo) && acc[obj.Padre].Hijo.push(obj.Hijo);
//!acc[obj.Padre].Hijo.includes(obj.Hijo) && acc[obj.Padre].Hijo.push(obj.Description)
}
return acc;
}, {});
this.setState({
menuSubmenu: Object.keys(PadreMap).map((padre) => ({
menu: padre,
submenu: PadreMap[padre].Hijo,
id: PadreMap.Id,
descripcion: PadreMap[padre].Description,
url: PadreMap[padre].URL
}))
})
console.log(PadreMap);
})
}
render() {
if (this.state.menuSubmenu.length > 0) {
return(
<nav className="nav">
<div className="menu">
<ul className="list">
{this.state.menuSubmenu.map(datos => <Menu key={datos.id} menu={datos.menu} submenu={datos.submenu} descripcion={datos.descripcion} submenuClick={this.submenuClick} abrirSubmenu={this.state.abrirSubmenu}/>)}
</ul>
<div className="content-bnt">
<button id="desplegar" className='btn btn--rounded'>
<Icon icon="flecha" className='ico-flecha'/>
</button>
</div>
</div>
</nav>
);
}
return (<p>Cargando usuarios...</p>);
}
}
class Menu extends Component{
render(){
return (
<li key={this.props.id} className="list__item">
<button title={this.props.menu} id={"mn-" + this.props.menu} className="desplegable" onClick={this.props.submenuClick}><Icon icon="auriculares" className='ico-auriculares'/>{this.props.menu}</button>
{
this.props.abrirSubmenu
? (
<div id="sb-crm" className="submenu">
{this.props.submenu.map(hijo => <h3 className="nav--title"><Icon icon="descargar" className='ico-descargar'/>{hijo}</h3>)}
<ul className="list">
<li className="list__item">
{this.props.descripcion.map(tercerNivel => <a href={this.props.url} title={this.props.descripcion}>{tercerNivel}</a>)}
</li>
</ul>
</div>
)
: (
null
)
}
</li>
)
}
}
export default Nav;
I need to be able to use all the information of the json, not just "Padre" and "Hijo". I also need the information to be grouped by his "Padre"

This snippet should be suitable:
this.setState(
{
menuSubmenu: Object.keys(PadreMap).map((padre) => {
const {Padre, Hijo, ...rest} = PadreMap[padre];
return {
menu: padre,
submenu: Hijo,
...rest
}
})
}
)

Related

TypeError: this.state.data.map in reactjs

class Home extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch("https://reqres.in/api/users?page=2")
.then((res) => res.json())
.then((json) => {
this.setState({
isLoaded: true,
data: json,
});
});
}
render() {
var { isLoaded, data }= this.state;
if(!isLoaded){
return<div>Is isLoaded</div>
}
else{
return (
<div>
<ul>
{() =>
this.state.data.map((data, index) => (
<li key={index}>Email: {data.email}</li>
))
}
;
</ul>
</div>
);
}
}
}
export default Home;
Hii All , I know this question is asked many times but I cant figure it out I'am getting the error. I have checked for all the questions similar to this but haven't found specific solution if I use another link i.e, "https://jsonplaceholder.typicode.com/users" this one the code works fine .
The returned data from https://reqres.in/api/users?page=2 is not an array, but an object with a data property containing what you are looking for (an array). The result of the request is :
{"page":1,"per_page":6,"total":12,"total_pages":2,"data":[{"id":1,"email":"george.bluth#reqres.in","first_name":"George","last_name":"Bluth","avatar":"https://reqres.in/img/faces/1-image.jpg"},{"id":2,"email":"janet.weaver#reqres.in","first_name":"Janet","last_name":"Weaver","avatar":"https://reqres.in/img/faces/2-image.jpg"},{"id":3,"email":"emma.wong#reqres.in","first_name":"Emma","last_name":"Wong","avatar":"https://reqres.in/img/faces/3-image.jpg"},{"id":4,"email":"eve.holt#reqres.in","first_name":"Eve","last_name":"Holt","avatar":"https://reqres.in/img/faces/4-image.jpg"},{"id":5,"email":"charles.morris#reqres.in","first_name":"Charles","last_name":"Morris","avatar":"https://reqres.in/img/faces/5-image.jpg"},{"id":6,"email":"tracey.ramos#reqres.in","first_name":"Tracey","last_name":"Ramos","avatar":"https://reqres.in/img/faces/6-image.jpg"}],"support":{"url":"https://reqres.in/#support-heading","text":"To keep ReqRes free, contributions towards server costs are appreciated!"}}
So you cannot use map function, which is from the Array prototype, on the result of your request. You must access the data property first :
this.state.data.data.map((data, index) => ( // note the double data
<li key={index}>Email: {data.email}</li>
))
You could also assign json.data to the state.data to avoid the ugly .data.data :
this.setState({
isLoaded: true,
data: json.data, // note the .data
});
I think the problem is in brackets around your .map() method. Please try this
class Home extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch("https://reqres.in/api/users?page=2")
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
data: json,
});
});
}
render() {
const { isLoaded, data } = this.state;
if (!isLoaded) {
return <div>Is isLoaded</div>;
} else {
return (
<div>
<ul>
{data?.map((data, index) => {
return <li key={index}>Email: {data.email}</li>;
})}
</ul>
</div>
);
}
}
}
export default Home;
I don't see any error, it's working just fine.
Output:
Working Example: StackBlitz
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch('https://reqres.in/api/users?page=2')
.then((res) => res.json())
.then((json) => {
console.log(json.data);
this.setState({
isLoaded: true,
data: json.data,
email: null,
});
});
}
render() {
var { isLoaded, data } = this.state;
if (!isLoaded) {
return <div>Is isLoaded</div>;
} else {
return (
<div>
<div className="contents home">
<img
src="https://trucard.io/india/wp-content/uploads/2021/08/2021-June-TruCard-Logo.png
"
width={50}
alt="img"
className="trucard-img"
/>
</div>
<div className="button">
<button className="button-button">Load list</button>
</div>
<ul>
{this.state.data?.map((data, index) => (
<li key={index}>Email: {data.email}</li>
))}
;
</ul>
</div>
);
}
}
}
export default App;

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)

Adding clicked items to new array in React

I am making API calls and rendering different components within an object. One of those is illustrated below:
class Bases extends Component {
constructor() {
super();
this.state = {
'basesObject': {}
}
}
componentDidMount() {
this.getBases();
}
getBases() {
fetch('http://localhost:4000/cupcakes/bases')
.then(results => results.json())
.then(results => this.setState({'basesObject': results}))
}
render() {
let {basesObject} = this.state;
let {bases} = basesObject;
console.log(bases);
//FALSY values: undefined, null, NaN, 0, false, ""
return (
<div>
{bases && bases.map(item =>
<button key={item.key} className="boxes">
{/* <p>{item.key}</p> */}
<p>{item.name}</p>
<p>${item.price}.00</p>
{/* <p>{item.ingredients}</p> */}
</button>
)}
</div>
)
}
}
The above renders a set of buttons. All my components look basically the same.
I render my components here:
class App extends Component {
state = {
ordersArray: []
}
render() {
return (
<div>
<h1>Bases</h1>
<Bases />
<h1>Frostings</h1>
<Frostings />
<h1>Toppings</h1>
<Toppings />
</div>
);
}
}
I need to figure out the simplest way to, when a button is clicked by the user, add the key of each clicked element to a new array and I am not sure where to start. The user must select one of each, but is allowed to select as many toppings as they want.
Try this
We can use the same component for all categories. All the data is handled by the parent (stateless component).
function Buttons({ list, handleClick }) {
return (
<div>
{list.map(({ key, name, price, isSelected }) => (
<button
className={isSelected ? "active" : ""}
key={key}
onClick={() => handleClick(key)}
>
<span>{name}</span>
<span>${price}</span>
</button>
))}
</div>
);
}
Fetch data in App component, pass the data and handleClick method into Buttons.
class App extends Component {
state = {
basesArray: [],
toppingsArray: []
};
componentDidMount() {
// Get bases and toppings list, and add isSelected attribute with default value false
this.setState({
basesArray: [
{ key: "bases1", name: "bases1", price: 1, isSelected: false },
{ key: "bases2", name: "bases2", price: 2, isSelected: false },
{ key: "bases3", name: "bases3", price: 3, isSelected: false }
],
toppingsArray: [
{ key: "topping1", name: "topping1", price: 1, isSelected: false },
{ key: "topping2", name: "topping2", price: 2, isSelected: false },
{ key: "topping3", name: "topping3", price: 3, isSelected: false }
]
});
}
// for single selected category
handleSingleSelected = type => key => {
this.setState(state => ({
[type]: state[type].map(item => ({
...item,
isSelected: item.key === key
}))
}));
};
// for multiple selected category
handleMultiSelected = type => key => {
this.setState(state => ({
[type]: state[type].map(item => {
if (item.key === key) {
return {
...item,
isSelected: !item.isSelected
};
}
return item;
})
}));
};
// get final selected item
handleSubmit = () => {
const { basesArray, toppingsArray } = this.state;
const selectedBases = basesArray.filter(({ isSelected }) => isSelected);
const selectedToppings = toppingsArray.filter(({ isSelected }) => isSelected);
// submit the result here
}
render() {
const { basesArray, toppingsArray } = this.state;
return (
<div>
<h1>Bases</h1>
<Buttons
list={basesArray}
handleClick={this.handleSingleSelected("basesArray")}
/>
<h1>Toppings</h1>
<Buttons
list={toppingsArray}
handleClick={this.handleMultiSelected("toppingsArray")}
/>
</div>
);
}
}
export default App;
CSS
button {
margin: 5px;
}
button.active {
background: lightblue;
}
I think the following example would be a good start for your case.
Define a handleClick function where you can set state with setState as the following:
handleClick(item) {
this.setState(prevState => {
return {
...prevState,
clickedItems: [...prevState.clickedItems, item.key]
};
});
}
Create an array called clickedItems in constructor for state and bind handleClick:
constructor() {
super();
this.state = {
basesObject: {},
clickedItems: [],
}
this.handleClick = this.handleClick.bind(this);
}
You need to add a onClick={() => handleClick(item)} handler for onClick:
<button key={item.key} className="boxes" onClick={() => handleClick(item)}>
{/* <p>{item.key}</p> */}
<p>{item.name}</p>
<p>${item.price}.00</p>
{/* <p>{item.ingredients}</p> */}
</button>
I hope that helps!

Reactjs having problems printing out fetched data

super noob question. However, I've been stuck with this issue for long enough now. I've been searching and have found the similar issue but have not been able to resolve it. I was hoping someone could point me in the right direction as to what I am doing wrong.
I am fetching data from an API, and I am able to log out the array, however, when I try to print it out I am having no luck. In the beginning, I was passing it through a reducer but then realized that was not ideal. Right now I am trying to get it to work, then I'll refactor the code into a functional component.
fetchOrders = async () => {
await axios.get('http://localhost:4200/ordenes').then( res => {
this.setState({
prescription: res.data
})
})
}
render() {
console.log(this.state.prescription)
return (
<div >
<Paper style={styles.orderCard}id='orderCardContainer' >
<div id="profileCardContainer" style={styles.profileCard}>
<aside className='profileCardContainer'>
<ProfileCard />
</aside>
</div>
{this.renderOrder()}
</Paper>
</div>
)
}
}
The array I receive back from the API looks something like this:
Array(18)
0: {order: Array(3), _id: "5b2af38fb315eb5630a0bc78", physicianName: "Alejandro", patientName: "Alex", createdAt: "2018-06-21T00:38:39.376Z", …}
UPDATE:
class OrderCard extends Component {
constructor(props) {
super(props)
this.state = { prescription: []}
}
fetchOrders = async () => {
const res = await axios.get('http://localhost:4200/ordenes')
this.setState({
prescription: res.data
})
}
componentDidMount() {
this.fetchOrders()
}
renderOrder() {
if (this.state.prescription.length === 0 ) {
return (
<h1>Loading...</h1>
)
} else {
return (
this.state.prescription.map( (x, i) => {
<li>
{console.log(x.patientName)}
<h1>{ x.patientName }</h1>
</li>
})
)}
}
render() {
console.log(this.state.prescription)
return (
<div >
<Paper style={styles.orderCard}id='orderCardContainer' >
<div id="profileCardContainer" style={styles.profileCard}>
<aside className='profileCardContainer'>
<ProfileCard />
</aside>
</div>
<div id='orders' >
{ this.renderOrder() }
</div>
</Paper>
</div>
)
}
}
function mapStateToProps(state) {
return {
auth: state.auth.authenticated,
}
}
export default connect(mapStateToProps, actions)(OrderCard)
BACKEND SCHEMA
const orderObj = new Schema({
name: String,
price: Number,
}, { _id : false })
const orderSchema = new Schema (
{
physicianName: String,
patientName: String,
order: {type: [orderObj]}
},
{
timestamps: true
}
)
POSTMAN API RESULTS
[
{
"order": [
{
"name": "Asteraceae",
"price": 41.24
},
{
"name": "Liliaceae",
"price": 39.24
},
{
"name": "Fabaceae",
"price": 34.91
}
],
"_id": "5b2af38fb315eb5630a0bc78",
"physicianName": "Alejandro",
"patientName": "Alex",
"createdAt": "2018-06-21T00:38:39.376Z",
"updatedAt": "2018-06-21T00:38:39.376Z",
"__v": 0
}
]
Thanks in advance for tips.
Wrong brackets, you're not returning react element, try fixed one.
renderOrder() {
if (this.state.prescription.length === 0 ) {
return (
<h1>Loading...</h1>
)
} else {
return (
this.state.prescription.map((x, i) => (
<li>
{console.log(x.patientName)}
<h1>{ x.patientName }</h1>
</li>
))
)}
}
and fix this
fetchOrders = async () => {
const res = await axios.get('http://localhost:4200/ordenes');
this.setState({
prescription: res.data
});
}

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