I recursively mapped nested JSON, and console log output all elements in format: property => value correctly, but components do not render. Following is JSON:
{
"index": "dwarf",
"name": "Dwarf",
"speed": 25,
"ability_bonuses": [
{
"ability_score": {
"index": "con",
"name": "CON",
"url": "/api/ability-scores/con"
},
"bonus": 2
}
],
"alignment": "Most dwarves are lawful, believing firmly in the benefits of a well-ordered society. They tend toward good as well, with a strong sense of fair play and a belief that everyone deserves to share in the benefits of a just order.",
"age": "Dwarves mature at the same rate as humans, but they're considered young until they reach the age of 50. On average, they live about 350 years.",
"size": "Medium",
"size_description": "Dwarves stand between 4 and 5 feet tall and average about 150 pounds. Your size is Medium.",
"starting_proficiencies": [
{
"index": "battleaxes",
"name": "Battleaxes",
"url": "/api/proficiencies/battleaxes"
},
{
"index": "handaxes",
"name": "Handaxes",
"url": "/api/proficiencies/handaxes"
},
{
"index": "light-hammers",
"name": "Light hammers",
"url": "/api/proficiencies/light-hammers"
},
{
"index": "warhammers",
"name": "Warhammers",
"url": "/api/proficiencies/warhammers"
}
],
"starting_proficiency_options": {
"choose": 1,
"type": "proficiencies",
"from": [
{
"index": "smiths-tools",
"name": "Smith's tools",
"url": "/api/proficiencies/smiths-tools"
},
{
"index": "brewers-supplies",
"name": "Brewer's supplies",
"url": "/api/proficiencies/brewers-supplies"
},
{
"index": "masons-tools",
"name": "Mason's tools",
"url": "/api/proficiencies/masons-tools"
}
]
},
"languages": [
{
"index": "common",
"name": "Common",
"url": "/api/languages/common"
},
{
"index": "dwarvish",
"name": "Dwarvish",
"url": "/api/languages/dwarvish"
}
],
"language_desc": "You can speak, read, and write Common and Dwarvish. Dwarvish is full of hard consonants and guttural sounds, and those characteristics spill over into whatever other language a dwarf might speak.",
"traits": [
{
"index": "darkvision",
"name": "Darkvision",
"url": "/api/traits/darkvision"
},
{
"index": "dwarven-resilience",
"name": "Dwarven Resilience",
"url": "/api/traits/dwarven-resilience"
},
{
"index": "stonecunning",
"name": "Stonecunning",
"url": "/api/traits/stonecunning"
},
{
"index": "dwarven-combat-training",
"name": "Dwarven Combat Training",
"url": "/api/traits/dwarven-combat-training"
},
{
"index": "tool-proficiency",
"name": "Tool Proficiency",
"url": "/api/traits/tool-proficiency"
}
],
"subraces": [
{
"index": "hill-dwarf",
"name": "Hill Dwarf",
"url": "/api/subraces/hill-dwarf"
}
],
"url": "/api/races/dwarf"
}
Then this is code:
import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'
import TypeComponent from './type_component'
import TestComponent from './test_component'
class raceWindow extends Component {
constructor(props)
{
super(props)
this.state = {
data: {}
}
}
componentDidMount()
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
componentDidUpdate(prevProps)
{
if(this.props.hdAPI !== prevProps.hdAPI)
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
}
isType (attr, value)
{
if(Array.isArray(value))
{
value.map((v) => {
Object.entries(v).map(([a1,v1]) => this.isType(a1,v1))
})
}
else
{
if(typeof value === 'object')
{
Object.entries(value).map(([a,v]) => this.isType(a,v))
}
else
{
console.log(attr);
console.log(value);
return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
}
}
};
render()
{
const { data} = this.state;
//I also tried to do the recursive map in a component, but it does not work either
/*
return(
<div>
<Grid container columns = {10}>
<TypeComponent attr = {""} value = {data} />
</Grid>
</div>
);*/
return(
<div>
<Grid container columns = {10}>
{this.isType("",data)}
</Grid>
</div>
);
}
}
export default raceWindow
When I tried to map it manually in the first layer, only first layer components rendered. Nested data in deeper layers do not render, though console output the deeper data correctly. So I assume react do not render deeper component. How should I deal with this?
Edit: Just note, I may be wrong, but I think every loop of isType() will go to this part of code at last:
else
{
console.log(attr);
console.log(value);
return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
}
console also output all non-array, non-object value in the log, but return() in this block does not render.
First let's look at the main problems you have right now:
The if blocks inside your isType function do not return anything. You are running functions against the value argument, but then you're not doing anything with what those functions return. Fixing this can be as simple as changing value.map... to value = value.map..., but if you don't do something, then when you get to the return at the end, those if blocks will have no impact on the final result.
Inside the first if block, your value.map... function doesn't return anything since you have brackets around Object.entries.... You just need to return Object.entries..., or else remove the brackets.
If we fix those problems and simplify the if/else logic a bit, we end up getting something back in the JSX:
isType(attr, value) {
let returnValue = value;
if (Array.isArray(returnValue)) {
returnValue = value.map((v) => {
return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
});
} else if (typeof returnValue === "object") {
returnValue = Object.entries(value).map(([a, v]) => this.isType(a, v));
}
return (
<Grid.Column>
<Label>{attr}</Label>
{returnValue}
</Grid.Column>
);
}
But you'll see when you get this far that the resulting DOM probably isn't what you want.
Instead, I recommend changing the approach a bit so that we first convert our JSON into a structure we can use and then map over it in our render function. This will hopefully also make it a little easier to reason about what is happening when and to modify your function to only add things to the final output that you actually care about.
That'd look something like this:
class RaceWindow extends Component {
constructor(props) {
super(props);
// your JSON; store in state if necessary
this.data = {};
// create a placeholder variable
this.finalDom = [];
// call `this.isType` to fill in that variable
// the result is a giant array of shape {attr: 'str', value: 'str'}
this.isType("", this.state.data);
}
isType(attr, value) {
if (typeof value === "string") {
this.finalDom.push({
attr,
value
});
}
if (Array.isArray(value)) {
this.finalDom.push({
attr,
value: value.map((v) => {
return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
})
});
}
if (typeof value === "object") {
this.finalDom.push({
attr,
value: Object.entries(value).map(([a, v]) => this.isType(a, v))
});
}
}
render() {
return (
<div>
<div class="container">
{this.finalDom.map((obj) => (
<div class="item">
<div class="label">{obj.attr}</div>
{obj.value}
</div>
))}
</div>
</div>
);
}
}
CodeSandbox demo of the above.
Final note: Make sure you capitalize the first letter of your component, or else React won't recognize it as a component.
Following is working code:
import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'
import TypeComponent from './type_component'
import TestComponent from './test_component'
class raceWindow extends Component {
constructor(props)
{
super(props)
this.state = {
data: {}
}
}
componentDidMount()
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
componentDidUpdate(prevProps)
{
if(this.props.hdAPI !== prevProps.hdAPI)
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
}
isType (attr, value, obj)
{
if(Array.isArray(value))
{
value.map((v) => {
Object.entries(v).map(([a1,v1]) => this.isType(a1,v1,obj))
})
}
else
{
if(typeof value === 'object')
{
Object.entries(value).map(([a,v]) => this.isType(a,v,obj))
}
else
{
var pair = {}
pair[attr] = value
obj.push(pair);
}
}
};
render()
{
const { data} = this.state;
var obj = [];
return(
<div>
<Grid container columns = {5}>
{this.isType("",data,obj)}
{
obj.map((arr, i) => {
return(
Object.entries(arr).map(([a,v]) => {
return(
<Grid.Column key = {i}><Label key = {i} color = 'orange'>{a}</Label>{v}</Grid.Column>
);
})
);
})
}
</Grid>
</div>
);
}
}
export default raceWindow
Thanks cjl750's advice, I use an variable to collect results from recursive function and it works. I also tried to let very if block has a return as his advice, but components still do not render. Not sure why.
For now, it seems jsx returned from deep layer in recursive function do not render.
Related
I created a child component by react-select, but options don't show up in first click on selector.
For the second time each section is clicked, the options are displayed. I tried to use the AsyncSelect but again it did not work.
The Data is read from Local Storage, but I don't think there is a problem with this.
Sandbox:
https://codesandbox.io/s/strange-field-4elv3?file=/src/App.js
My data from local storage:
const feauters = [
{
"id": 5,
"title": "Type",
"options": [
{
"id": 231040,
"name": "cloth",
"property": 5
},
{
"id": 230081,
"name": "Synthetic materials",
"property": 5
}
]
},
{
"id": 646,
"title": "Shoe soles",
"options": [
{
"id": 231063,
"name": "Abrasion resistant",
"property": 646
},
{
"id": 231064,
"name": "Reduce the pressure",
"property": 646
}
]
},
]
Parent Component:
<MultiSelect features={features} />
My Component:
import React, {useEffect, useState} from 'react';
import {Form} from 'react-bootstrap';
import Select from 'react-select';
const MultiSelect = ({features}) => {
// Declare States
const [selectors, setSelectors] = useState([]);
// Handle Features
useEffect(() => {
const initialSelectors = features.map((item, index, array) => {
const options = item.options.map((subItem) => {
return {
value: `${subItem.property}-${subItem.id}`,
label: subItem.name,
};
});
return (
<React.Fragment key={`product-multiselect-${index}-${item.id}`}>
<Form.Label htmlFor={`product-multiselect-${index}-${item.id}`}>{item.title}</Form.Label>
<Select
id={`product-multiselect-${index}-${item.id}`}
className="mb-2"
classNamePrefix="select"
defaultInputValue="Select..."
placeholder="Select..."
noOptionsMessage={() => 'Not Found.'}
isMulti
isClearable
isRtl
isSearchable
name={item.title}
onChange={handleChangeInput}
options={options}
/>
</React.Fragment>
);
});
setSelectors(initialSelectors);
}, [features]);
// Handle Change Input
const handleChangeInput = (values) => {
console.log(values);
};
return selectors;
};
export default MultiSelect;
First of all as mentioned in the comments you shouldn't store the component inside the state. Related question
Secondary, options don't show up because of defaultInputValue props. If you remove it, the component would work as intended
Very new to React, so I might be approaching this the wrong way... I want my app to take input from a text input field, retrieve a JSON from the reddit API (the url is built from the text input), and then render data from the JSON, looping through each of the entries. I'm using useState to trigger the data render. I can successfully retrieve the data and output specific values, but I want to be able to have a loop that dynamically outputs the data into various HTML elements.
Here's what I have so far that allows me to output some specific values as an example:
import React, { useState } from 'react';
const App = () => {
const [retrievedData, setRetrievedData] = useState([])
const runSearch = async() => {
const searchInput = document.getElementById('searchInput').value
const searchUrl = 'https://www.reddit.com/r/' + searchInput + '/new/.json?limit=5'
const response = await fetch(searchUrl)
const redditResponse = await response.json()
setRetrievedData(<>
<p>{JSON.stringify(redditResponse.data.children[0].data.author)}</p>
<p>{JSON.stringify(redditResponse.data.children[0].data.title)}</p>
</>)
}
return (
<>
<section>
<input type="text" id='searchInput' placeholder='Enter a subreddit...'></input>
<button onClick={runSearch}>
Get Data
</button>
<div>{retrievedData}</div>
</section>
</>
);
};
export default App;
And here's an example of the JSON that is retrieved from the reddit API, just stripped down with only the example values I use in my code above:
{
"kind": "Listing",
"data": {
"modhash": "",
"dist": 5,
"children": [
{
"kind": "t3",
"data": {
"author": "author1",
"title": "title1"
}
},
{
"kind": "t3",
"data": {
"author": "author2",
"title": "title2"
}
},
{
"kind": "t3",
"data": {
"author": "author3",
"title": "title3"
}
},
{
"kind": "t3",
"data": {
"author": "author4",
"title": "title4"
}
},
{
"kind": "t3",
"data": {
"author": "author5",
"title": "title5"
}
}
],
"after": "t3_jnu0ik",
"before": null
}
}
I just need the final rendered output to be something like:
<h2>TITLE 1</h2>
<h4>AUTHOR 1</h4>
<p>SELFTEXT 1</p>
...and repeated for each post data that is retrieved.
I've seen a variety of different ways to render JSON data and many of them show either loops and/or the .map() method, but I can't ever seem to get those to work, and wonder if it's an issue with the useState. Perhaps there is some way I should be rendering the data some other way?
You don't need set jsx to state, you can directly iterate children data with map
Try this
const App = () => {
const [retrievedData, setRetrievedData] = useState([])
const runSearch = async() => {
const searchInput = document.getElementById('searchInput').value
const searchUrl = 'https://www.reddit.com/r/' + searchInput + '/new/.json?limit=5'
const response = await fetch(searchUrl)
const redditResponse = await response.json()
if (redditResponse.data.children && redditResponse.data.children.length) {
setRetrievedData(redditResponse.data.children)
}
}
return (
<>
<section>
<input type="text" id='searchInput' placeholder='Enter a subreddit...'></input>
<button onClick={runSearch}>
Get Data
</button>
<div>
{
retrievedData.map((children, index) => {
return (
<div key={children.data.author + index}>
<div>Kind: { children.kind }</div>
<div>Author: { children.data.author }</div>
<div>Title: { children.data.title }</div>
</div>
)
})
}
</div>
</section>
</>
);
};
I am using react-dnd drag and drop and have a sorted list that gets mapped through, it works somewhat I am able to drag and drop and on refresh it seems things stayed in the right position but the element moves one row than where I dragged it.
The main issue is when I drag the item and drop it the cards state in the moveCardDb is different slightly then outside the function, why it would be different at that point I can't seem to figure out.
Here is a minimal setup of what I have
https://codesandbox.io/s/gifted-goodall-qu43p?file=/src/Container.jsx
If you look at the console log on the moveCardDb function you will see the cards stae variable slightly out of order
Thanks ahead of time
I have the following code for the drag and drop
The mapping function and update of position
const [cards, setCards] = useState([]);
let stateReplace = useMemo(() => {
if (!isLoading && formBuilder?.inputs?.length) {
return formBuilder.inputs;
}
return [];
}, [isLoading]);
useEffect(() => {
setCards(stateReplace);
}, [setCards, stateReplace]);
// console.log(cards);
const moveCard = useCallback(
(dragIndex, hoverIndex) => {
console.log(dragIndex);
console.log(hoverIndex);
const dragCard = cards[dragIndex];
setCards(
update(cards, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragCard],
],
})
);
},
[cards]
);
const moveCardDb = useCallback(() => {
//console.log(cards);
Meteor.call("formLeadBuilderDrag.update", cards, params._id, function (
error,
result
) {
console.log(result);
console.log(error);
});
}, [cards]);
const renderCard = (card, index) => {
return (
<>
{isLoading ? (
<div className="loading">loading...</div>
) : (
<>
<Card
key={card.dragPositionId}
index={index}
id={card.dragPositionId}
input={card.inputType}
moveCard={moveCard}
moveCardDb={moveCardDb}
/>
</>
)}
</>
);
};
return (
<>
{isLoading ? (
<div className="loading">loading...</div>
) : (
<form>
<div style={style}>{cards.map((card, i) => renderCard(card, i))}</div>
<input type="submit" />
</form>
)}
</>
);
The card rendered
import React, { useRef } from "react";
import { useDrag, useDrop } from "react-dnd";
import { ItemTypes } from "./ItemTypes";
const style = {
border: "1px dashed gray",
padding: "0.5rem 1rem",
marginBottom: ".5rem",
backgroundColor: "white",
cursor: "move",
};
export const Card = ({ id, input, index, moveCard, moveCardDb }) => {
const ref = useRef(null);
const [, drop] = useDrop({
accept: ItemTypes.CARD,
hover(item, monitor) {
if (!ref.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ref.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(dragIndex, hoverIndex);
moveCardDb();
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
},
});
const [{ isDragging }, drag] = useDrag({
item: { type: ItemTypes.CARD, id, index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
const opacity = isDragging ? 0 : 1;
drag(drop(ref));
return (
<div ref={ref} style={{ ...style, opacity }}>
<p>{input}</p>
<input
name={input + id}
defaultValue="test"
// ref={register}
/>
{/* <button type="button" onClick={onEditToggle}>
<BiEditAlt size={25} />
</button> */}
{/* <button onClick={() => deleteLead(leads)}>×</button> */}
</div>
);
};
My Object from the beginning
{
"_id": "showRoomId",
"type": "Show Room Lead",
"createdAt": "2020-11-14",
"userId": "83nfd298dn382",
"inputs": [
{
"inputType": "shortText",
"dragPositionId": "1",
"label": "First Name:"
},
{
"inputType": "phoneNumber",
"dragPositionId": "2",
"label": "Cell Phone Number"
},
{
"inputType": "email",
"dragPositionId": "3",
"label": "Work Email"
},
{
"inputType": "Address",
"dragPositionId": "4",
"label": "Home Address"
},
{
"inputType": "multipleChoice",
"dragPositionId": "5",
"label": "Preferred Method of Contact",
"options": [
{
"dragPositionId": "1",
"label": "Email"
},
{
"dragPosition": "2",
"label": "Cell Phone"
}
]
},
{
"inputType": "dropDown",
"dragPositionId": "6",
"label": "How did you find us?",
"options": [
{
"dragPositionId": "1",
"label": "Google"
},
{
"dragPosition": "2",
"label": "Referral"
}
]
}
]
}
You have provided a bunch of code, which is good, but I am not clear on where the problem is, and the things you have tried to attempt to remedy it. Are things stored in the DB as you expect, or is it a rendering problem?
I ended up putting a time on a function on the monitor.didDrop function. It seems a bit hacky to me, so if anyone can offer a better solution let me know. I also decided to store to localstorage first, and then wil submit to database on form submit.
const [{ isDragging, didDrop }, drag] = useDrag({
item: { type: ItemTypes.CARD, id, index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
didDrop: monitor.didDrop(),
}),
});
const opacity = isDragging ? 0 : 1;
function droppy(dropped) {
var delayInMilliseconds = 1000; //1 second
setTimeout(function () {
dropped();
}, delayInMilliseconds);
}
if (didDrop) {
droppy(moveCardDb);
}
I'm new to React-Native and I'm learning this by tutorials and examples all over the web. I am trying to do something very simple but it has been a week since I hit this problem and after digging StackOverflow and many other contents, none of them could help. So I decided to ask it directy. My apologies if the question looks duplicate or it seems silly.
I am trying to iterate over a JSON object and display it. All I want to do right now is to show each JSON object with its title (username). I'm planning to do much more - make the title a button and show the details of user after hitting button - but right now this is the big rock I've hit into.
Here is my code. Please note my comment on fetchdata method :
import React, { Component } from 'react'
import { View, Text, FlatList, TouchableOpacity, ListView } from 'react-native'
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const textColor = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{ color: textColor }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}
export default class HttpExample extends Component {
constructor(props) {
super(props);
this.state = {
data: '',
username: [],
first_name: '',
last_name: ''
};
//Using ES6 we need to bind methods to access 'this'
this.fetchData = this.fetchData.bind(this);
}
componentDidMount() {
this.fetchData();
}
fetchData() {
// The first line - which is commented - returns all of non-admin
// users, the second one returns only one user. Note that the
// second one works fine and the first one does not.
// fetch('http://URL/users.json', {
fetch('http://URL/users/12345678001.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson,
username: responseJson.username,
first_name: responseJson.first_name,
last_name: responseJson.last_name
})
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item}
onPressItem={this._onPressItem}
title={this.state.username}
/>
);
render() {
return (
<FlatList
data={[this.state.data]}
renderItem={this._renderItem}
/>
)
}
}
And here is a sample of one of my JSON objects created by Django ReST framework, written by myself. I've just simplified the object a bit and removed some of the fields, for better reading (The avatar field is a base64 image field and it is much smaller than the original one):
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}
The above is what I get by calling http://URL/users/12345678001.json which returns one user. I have been able to show the user as one touchable opacity in the application (the above code works) But when I call users.json which has a structure like below:
[{user1 data},{user2 data}, etc.]
I cannot make the mobile application display each user's username in the mobile output. Either I get nothing (nothing is displayed) or the usual errors pop up (TypeError: object is not a function, etc.) I want to have the application iterate through the whole users.json and show each user's username as one touchable opacity. I've tried using .map which throws me the error, or calling each object in responseJson by their array index which either shows me nothing or throws error.
Let me know about your ideas and solutions.
FYI, I am testing this on my Nexus 5X phone directly.
Update
Here is an example of users.json as it reflects in my console log :
[{
"username": "12345678001",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
},
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678003",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-12-20",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}]
Another Update
As requested, here is a screenshot of my console, note that it differs from what I've posted here and has many different fields :
More Investigation:
I decided to make the code much simpler, and just focus on the main problem. How to return the iterated object for display:
My code is now this:
import React, { Component } from 'react'
import { View, Text, ListView } from 'react-native'
export default class HttpExample extends Component {
constructor(props) {
super(props);
data = [''];
}
fetchData() {
fetch('http://URL/users.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log("ResponseJson is :" + responseJson);
console.log(responseJson.users.length);
console.log(responseJson.users.username);
console.log(responseJson.users);
console.log("THIS:::" + responseJson.users[0].username);
responseJson.users.map((user) =>
{
console.log("THIS:::" + user.username);
data.push(user.username);
console.log("This.data:" + data[0] + "second:" + data[1]);
});
return data;
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
render() {
return (
<View>
<ListView
dataSource={this.fetchData()}
renderRow={(data) => <Text>{data.username}</Text>}
/>
</View>
)
}
}
All of the "console.log" commands return with correct info (Check the end of the post), but my render does not work and throws undefined is not a object. I really don't understand what is the exact problem? isn't data an array? Why it can't be displayed and throws TypeError? What am I getting wrong?
console.log outputs, in correct order :
ResponseJson is :[object Object]
3
undefined
(whole users.json is returned)
THIS:::12345678001
THIS:::12345678001
This.data:second:12345678001
THIS:::12345678002
This.data:second:12345678001
THIS:::12345678003
This.data:second:12345678001
I've been struggling with this all day. Really new to react so apologies in advanced.
I'm trying to use react-jsonschema-form to create form from json with react-color.
This is what I have now:
import React, {Component} from "react";
import {ChromePicker} from 'react-color';
import Form from "react-jsonschema-form";
const ColorPicker = (props) => {
return (
<ChromePicker
color={props.value || false}
value={props.value}
onChange={(event) => {
props.onChange(event.color)
}}
/>
)
}
const schema = {
"type": "object",
"properties": {
"base": {
"type": "object",
"title": "Global settings",
"properties": {
"line-height": {
"title": "Body line height",
"type": "number"
},
"background-color": {
"title": "Body background color",
"type": "string"
},
"font-color": {
"title": "Body background color",
"type": "string"
}
}
}
}
}
const uiSchema = {
base:{
"background-color":{
'ui:widget':ColorPicker
},
"font-color":{
'ui:widget':ColorPicker
}
}
}
export default class GeneratorForm extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(data) {
console.log(data)
}
render() {
return (
<Form schema={schema}
uiSchema={uiSchema}
//onBlur={this.handleSubmit}
onChange={this.handleChange}
//onSubmit={this.handleSubmit}
onError={log("errors")}/>
);
}
}
Simple form with two colorpickers. And the colorpicker works great, except in the handleChange, formData for that field is empty. It's like the value isn't assigned. I've searched for similar topics, somethings similar with datepicker3 and that gave me an idea to make it simple (had some crazy code, custom class component and so on).
So the question is, how to pass a value from color picker to form value?
Thanks in advance.
You should take a look at the Docs for react-color. You aren't handling the onChange event correctly. It should be:
const ColorPicker = (props) => {
return (
<ChromePicker
color={props.value || false}
value={props.value}
onChange={ color => {
props.onChange(color)
}}
/>
)
}
event.color doesn't exist. The onChange handler will get two arguments, color and event.