I want to display Json Data in a Flatlis component in my react-native App, but i can't figure out how to display it. I want to show the name of the dinosaur in a List and if i press on the list item i want to show the dimensions of the dinosaur.
I have the List items and the Detail screen all set up, but i get a blank screen with this code, did I import the JSON data in a wrong way or do i somehow have to restructure the data to display it?
I have JSON data like this:
{
"lambeosaurus": {
"dimensions": {
"height": 2.1,
"length": 12.5,
"weight": 5000
}
},
"stegosaurus": {
"dimensions": {
"height": 4,
"length": 9,
"weight": 2500
}
}
}
and this is my Code:
import React from 'react'
import { StyleSheet, Text, View, TouchableOpacity, StatusBar, FlatList, Image } from 'react-native'
import MyListItem from '../components/MyListItem'
const data = require("../data/MockData.json")
class HomeScreen extends React.Component {
render() {
return (
<View>
<StatusBar hidden={true} />
<FlatList
data={data}
renderItem={({ item }) =>
<MyListItem
item={item}
onPress={() => {
this.props.navigation.navigate('Details', {
item: item
})
}}
/>
}
/>
</View>
);
}
}
export default HomeScreen;
FlatList expects an array as data prop, but your JSON is an object. You could change it into an array before using it.
// const objData = require("../data/MockData.json");
const objData = {
lambeosaurus: {
dimensions: {
height: 2.1,
length: 12.5,
weight: 5000
}
},
stegosaurus: {
dimensions: {
height: 4,
length: 9,
weight: 2500
}
}
};
const data = Object.keys(objData).map(key => ({
key,
...objData[key]
}));
console.log(data);
Related
I am learning RN and I am having trouble setting up a mapping method to go through an array of images of some players that I created in a local JSON file, and render them in their respective profile pages.
This is how I have set my json.
//PlayerImages.js
const PlayerImages = [
{
id: "1",
name: "Cristiano Ronaldo",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "2",
name: "Lionel Messi",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "3",
name: "Neymar",
images: mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "4",
name: "Gabriel de Jesus",
images:["https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg",
"https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg",
"https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg"]
},
{
id: "5",
name: "Roberto Firmino",
images:mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
}
]
export default PlayerImages;
This is how I have the ImageGallery component set up. Unfortunately, the way I have componentDidMount set up, shows Cristiano Ronaldos images in all profiles. How can I map it in order to make sure that each profile has the pictures of that particular player when you tap the gallery button on their profile?
//ImageGallery.js
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { SliderBox } from "react-native-image-slider-box";
import { withNavigation } from "react-navigation";
import PlayerImages from "../Data/PlayerImages";
class ImageGallery extends React.Component {
static navigationOptions = {
title: "Player Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: "bold"
};
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
render() {
return (
<View style={styles.container}>
<SliderBox
images={this.state.images}
sliderBoxHeight={900}
onCurrentImagePressed={index =>
console.warn(`image ${index} pressed`)
}
dotColor="yellow"
inactiveDotColor="white"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default withNavigation(ImageGallery);
Finally, when you are on the players profile, you should have access to their gallery by tapping the button in the header. As I mentioned earlier in the post, when you tap it, you get only the images of Cristiano Ronaldo.
//PlayerProfile.js
headerRight: (
<Button
onPress={() => navigation.navigate("ImageGallery")}
title="Gallery"
color="#f6c945"
/>
)
Pass the id of the player or the index of the player you want to display images of using navigation parameters , then use it to get the images of the player, right now you are using images at the 0th index of array.
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
change this to
componentDidMount() {
let images = PlayerImages[index].images; //index is the index of the player whose images you want to show
this.setState({ images });
}
I am trying to create a dynamic photo gallery for all the characters on my app. When I click on the gallery for that particular character, It takes me to their gallery, but no images appear. Each character should have 3 images for their gallery. While the app does not break, I do get a warning message saying the following: "Failed prop type: Invalid prop source supplied to image." Can somebody look at my code and see where I am wrong?
I created a JSON file with images for each character.
//CharacterImages.js
const CharacterImages = [
{
id: "1",
name: "Homer Simpson",
urlone:
"https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg",
urltwo:
"https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg",
urlthree:
"https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg"
},
{
id: "2",
name: "Marge Simpson",
urlone:
"https://i.pinimg.com/564x/63/e4/7d/63e47d98e66622bbff5e4578ccffeffc.jpg",
urltwo:
"https://i.pinimg.com/564x/04/48/60/044860ebcd5d6c14a1140b351cb620b1.jpg",
urlthree:
"https://i.pinimg.com/564x/6d/99/26/6d9926fa54bc3650acf9295d997fc72c.jpg"
},
{
id: "3",
name: "Bart Simpson",
urlone:
"https://i.pinimg.com/564x/fe/18/af/fe18af309234936e231fa107c6d2b4c7.jpg",
urltwo:
"https://i.pinimg.com/564x/20/59/7a/20597ab32ab0f7ec8a5484fa384e0bb4.jpg",
urlthree:
"https://i.pinimg.com/564x/20/59/7a/20597ab32ab0f7ec8a5484fa384e0bb4.jpg"
}
export default CharacterImages;
I created a separate folder so that the images can come in dynamically.
// ImageGallery.js
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { SliderBox } from "react-native-image-slider-box";
import { withNavigation } from "react-navigation";
import CharacterImages from "../Data/CharacterImages";
class ImageGallery extends React.Component {
static navigationOptions = {
title: "Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: "bold"
};
constructor(props) {
super(props);
this.state = {
CharacterImages
};
}
render() {
return (
<View style={styles.container}>
<SliderBox
images={this.state.CharacterImages}
sliderBoxHeight={900}
onCurrentImagePressed={index =>
console.warn(`image ${index} pressed`)
}
dotColor="yellow"
inactiveDotColor="white"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default withNavigation(ImageGallery);
Finally, the user can access the each characters gallery when they are in that particular profile this way:
//CharacterProfile.js
headerRight: (
<Button
onPress={() => navigation.navigate("ImageGallery")}
title="Gallery"
color="#f6c945"
/>
)
The problem here is that you are passing a whole object of datas instead of an array of strings with urls.
Try changing images prop to:
images = {this.state.CharacterImages.urlone}
Then i would advise to create a single "image" key object with the array of strings, making your CharacterImages be:
const CharacterImages = [
{
id: "1",
name: "Homer Simpson",
images:["https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg",
"https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg",
"https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg"]
},
{
id: "2",
name: "Marge Simpson",
images:["https://i.pinimg.com/564x/63/e4/7d/63e47d98e66622bbff5e4578ccffeffc.jpg",
"https://i.pinimg.com/564x/04/48/60/044860ebcd5d6c14a1140b351cb620b1.jpg",
"https://i.pinimg.com/564x/6d/99/26/6d9926fa54bc3650acf9295d997fc72c.jpg"]
},
{
id: "3",
name: "Bart Simpson",
images:["https://i.pinimg.com/564x/fe/18/af/fe18af309234936e231fa107c6d2b4c7.jpg",
"https://i.pinimg.com/564x/20/59/7a/20597ab32ab0f7ec8a5484fa384e0bb4.jpg",
"https://i.pinimg.com/564x/20/59/7a/20597ab32ab0f7ec8a5484fa384e0bb4.jpg"]
}
]
export default CharacterImages;
EDIT
Forgot that CharacterImages is an Array of objects!!!
I updated also the constant as i didn't close the array
Here you have to decide how you want to render your images based of which condition. I'm going to show you how to put them so all images gets rendered:
constructor(props){
super(props)
mergedArray=CharacterImages.map(item=> item.images).concat.apply([], mergedArray)
this.state={
images=mergedArr
}
}
After this you can use this.state.images inside your SliderBox
I am creating a web app in ReactJS and I am trying to call an API from within my Chart class.
I have a program that takes data from a ML model and writes it to an API in the form of an array. I'm new to using ReactJS and I just want to make a call to the API to return the array into my data variable in react to render in the graph onscreen.
The data in the API is formatted as ..
[
1,
2,
3,
4
]
Currently I have the data hard coded into a separate file and am importing that but I want it to be called from the API directly so it updates.
import React, {Component} from "react"
import {Line} from "react-chartjs-2"
import {popuData, dayLabels} from "./FakeGraphData";
class PlanGraph extends Component{
constructor(props){
super(props);
this.state = {
chartData:{
labels: dayLabels,
datasets: [
{
label:'Predicted Park Crowds',
data: popuData,
borderColor: 'rgba(77, 112, 255, 1)',
backgroundColor: 'rgba(77, 112, 255, 1)'
}
]
}
}
}
render(){
return(
<div className = "chart">
<Line
data={this.state.chartData}
options={{
title: {
display:true,
text:"Predicted Park Crowds",
fontSize:25
},
legend:{
display: true,
position: 'right'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Anticipated Crowds'
},
ticks: {
beginAtZero: true
}
}],
xAxes: [{
scaleLabel: {
display:true,
labelString: 'Days in the future'
}
}]
}
}}
/>
</div>
)
}
}
export default PlanGraph
Add a container Component & use Props
The component you've shown us here looks like a presentational component (has html structure, cares about how things look). What you should do is create a container component, these components care about things like logic & getting data. You can read about this design methodology here.
The container will render the component you have posted above but will pass some props kind of like this.
Example
class PlanGraphContainer extends Component {
state = {
dataToPass: []
};
async componentDidMount() {
const response = await fetch('https://your-api-request');
const data = await response.json(); // maybe you need this, you have to check your response
this.setState({dataToPass: data});
}
render() {
return <PlanGraph data={this.state.dataToPass} />
}
}
Then inside your PlanGraph use this.props.data to see the data that is being passed. make sure you have some fake data or loading state whilst you wait for the request to be complete. our you can add something like this
render() {
const { dataToPass } = this.state;
return (dataToPass && dataToPass.length)
? <PlanGraph data={this.state.dataToPass} />
: null;
}
I'm currently trying to take some JSON data that I've received from an API and put that into a dropdown in a very simple React application.
This is my DropDown component thus far:
import React from 'react';
var values;
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then(function(json) {
values = json;
console.log(values);
});
class DropDown extends React.Component {
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
</div>;
}
}
export default DropDown;
Any my JSON looks like this:
{
"values":[
{
"id":0,
"name":"Jeff"
},
{
"id":1,
"name":"Joe"
},
{
"id":2,
"name":"John"
},
{
"id":3,
"name":"Billy"
},
{
"id":4,
"name":"Horace"
},
{
"id":5,
"name":"Greg"
}
]
}
I'd like the dropdown options to correspond to the 'name' of each element, and the 'id' to be used as an element identifier when an event is triggered by selecting an option. Any advice on getting this data into a dropdown which responds to user input would be greatly appreciated.
Call the API in componentDidMount lifecycle function of your React component and then save the response in state and then render the Select dropdown
import React from 'react';
class DropDown extends React.Component {
state = {
values: []
}
componentDidMount() {
fetch('http://localhost:8080/values')
.then(function(res) {
return res.json();
}).then((json)=> {
this.setState({
values: json
})
});
}
render(){
return <div className="drop-down">
<p>I would like to render a dropdown here from the values object</p>
<select>{
this.state.values.map((obj) => {
return <option value={obj.id}>{obj.name}</option>
})
}</select>
</div>;
}
}
export default DropDown;
You could do something like this:
import React from 'react';
var values;
class DropDown extends React.Component {
constructor(){
super();
this.state = {
options: []
}
}
componentDidMount(){
this.fetchOptions()
}
fetchOptions(){
fetch('http://localhost:8080/values')
.then((res) => {
return res.json();
}).then((json) => {
values = json;
this.setState({options: values.values})
console.log(values);
});
}
render(){
return <div className="drop-down">
<select>
{ this.state.options.map((option, key) => <option key={key} >{option}</option>) }
</select>
</div>;
}
}
export default DropDown;
Basically you are initializing state and setting options to null.
You are then fetching your options when the component mounts in the browser. These values are set to your state with this.setState().
Note: It is important to make any API calls in componentDidMount() and not componentWillMount(). If you call it in componentWillMount() the request will be made twice.
Then you render these options by mapping them in your render function
JSON FILE: terrifcalculatordata.json
[
{
"id": 1,
"name": "Vigo",
},
{
"id": 2,
"name": "Mercedes",
},
{
"id": 3,
"name": "Lexus",
},
{
"id": 4,
"name": "Buggati",
},
]
CODE:
1st import json file on top:
import calculatorData from "../static/data/terrifcalculatordata.json";
2nd in render method type this code:
<Form>
<FormGroup>
<Input
type="select"
onChange = {this.changeCarmodel}
value={this.state.changeCar}
>
{calculatorData.map((caldata, index) =>
<option
key={index}
value= {caldata.id}
> {caldata.name} </option>
)}
</Input>
</FormGroup>
</Form>
How to render JSON response as dropdown list in React.
export default class ExpenseNew extends Component {
constructor(){
super();
this.state={
PickerSelectedVal : '',
accountnameMain:[],
}
}
componentDidMount(){
var account_nam=[]
fetch('your Url', {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + your token }
})
.then((response) => response.json())
.then((customerselect) => {
// alert(JSON.stringify(customerselect))
global.customerdata = JSON.stringify(customerselect)
var customername = JSON.parse(customerdata);
//alert(JSON.stringify(customername));
for (i = 0; i < customername.cus_data.length; i++) {
var dataa = customername.cus_data[i]["account_name"];
account_nam.push(dataa)
}
this.setState({accountnameMain:account_nam});
})
.done();
}
render() {
return (
<Picker
selectedValue={this.state.PickerSelectedVal}
placeholder="Select your customer"
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
onValueChange={(itemValue, itemIndex) => this.setState({PickerSelectedVal: itemValue})} >
{this.state.accountnameMain.map((item, key)=>(
<Picker.Item label={item} value={item} key={key}/>)
)}
</Picker>
)
}
}
Hi I have this object and will have do some mathematical/statistical operations on it. Now I have to questions:
How do I access it? For Example I'd like to access numbers[0]['B1']
When I do {this.props.numbers[0]['B1']} I get: Cannot read property B1 of undefined.
If I want to do some calculations on those numbers, where would I put them? From my limited experience with react redux, I know I should not do anything like that in reducers, am I right? Would I create more actions (action creators) to eg. get the average B1 number, or any statistical operations on the numbers, etc. Would it be recommended to use 'reselect' for this kind of tasks?
numReducer
import { LIST_NUMBERS, PICK_NUMBER, GET_DATA } from '../actions/actionTypes';
export default (state = [], action = {}) => {
switch (action.type) {
case LIST_NUMBERS:
return action.payload || [];
case PICK_NUMBER:
return action.payload;
case GET_DATA:
return action.payload;
default:
return state;
}
};
actions:
import { LIST_NUMBERS, PICK_NUMBER, GET_DATA } from './actionTypes';
import dataSet from '../data.json';
export const listNumbers = () => {
const nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
return {
type: LIST_NUMBERS,
payload: nums
};
};
export const getData = () => {
return {
type: GET_DATA,
payload: dataSet
};
};
export const pickNumber = (num) => {
return {
type: PICK_NUMBER,
payload: num
};
};
data.json
[
{
"DrawDate": "22-Mar-17",
"B1": 12,
"B2": 6,
"B3": 11,
"B4": 31,
"B5": 27,
"B6": 19,
"BB": 42,
"BS": 1,
"DrawNumber": 2217
},
{
"DrawDate": "18-Mar-17",
"B1": 26,
"B2": 37,
"B3": 8,
"B4": 3,
"B5": 19,
"B6": 41,
"BB": 43,
"BS": 3,
"DrawNumber": 2216
},
....
Home Container
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { listNumbers, pickNumber, getData } from '../actions/numberActions';
import Home from '../components/Home';
const mapStateToProps = state => ({
numbers: state.numbers
});
const mapDispatchToProps = dispatch => (
bindActionCreators({
listNumbers,
pickNumber,
getData
}, dispatch)
);
export default connect(
mapStateToProps,
mapDispatchToProps
)(Home);
Home Component:
import React, { Component } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
export default class Home extends Component {
static navigationOptions = {
title: 'Home Screen',
};
componentDidMount() {
this.props.getData();
}
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.props.numbers[0]['B1']}</Text>
</View>
);
}
}
EDIT/ADDITION:
As per suggestions below, I've changed the lifecycle method to ComponentWillMount and added a check to see if this.props.numbers is loaded.
import React, { Component } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
export default class Home extends Component {
static navigationOptions = {
title: 'Home Screen',
};
componentWillMount() {
this.props.getData();
}
render() {
if (!this.props.numbers) {
console.log('not yet loaded'); // or a spinner?
}
const { navigate } = this.props.navigation;
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.props.numbers[0]['B1']}</Text>
</View>
);
}
}
I still get the same error: Cannot read property 'B1' of undefined. Additionally, the console does not log 'not yet loaded', which would indicate that the numbers object is there - I'm just making an error accessing it.
EDIT2:
import React, { Component } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
export default class Home extends Component {
static navigationOptions = {
title: 'Home Screen',
};
componentWillMount() {
this.props.getData();
}
listNums() {
return this.props.numbers.map((num) => num['B1']);
}
listSingleNum() {
return this.props.numbers[0]['B1'];
}
render() {
if (!this.props.numbers) {
console.log('not yet loaded'); // or a spinner?
} else {
console.log(this.listNums());
}
const { navigate } = this.props.navigation;
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.listNums()}</Text>
</View>
);
}
}
So listNums() works fine displaying B1s of each element but if I try to access a single B1 element as in listSingleNum, it throws the error mentioned before: ExceptionsManager.js:63Cannot read property 'B1' of undefined.
How do I access it? For Example I'd like to access numbers[0]['B1'] When I do {this.props.numbers[0]['B1']} I get: Cannot read property B1 of undefined.
It looks like all your react/redux wiring is fine, its just that getData is getting called in componentDidMount so for the first render, the data is not not there yet (see the docs for lifecycle methods order). You can use componentWillMount instead, but I'm still not sure if the data will be available on the first render. To be safe, change the render function to do something different if numbers is undefined (you would have to do this anyway if you ever end up loading the data from a backend somewhere).
NOTE: The following is incorrect - see edit below
render() {
if (!this.props.numbers) {
return null; // or a spinner?
}
const { navigate } = this.props.navigation;
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.props.numbers[0]['B1']}</Text>
</View>
);
}
If I want to do some calculations on those numbers, where would I put them? From my limited experience with react redux, I know I should not do anything like that in reducers, am I right? Would I create more actions (action creators) to eg. get the average B1 number, or any statistical operations on the numbers, etc. Would it be recommended to use 'reselect' for this kind of tasks?
This will depend on how intensive the calculations are. If the're pretty cheap, I'd just do them in the render function
import calculateAverage from './somewhere'
...
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.props.numbers[0]['B1']}</Text>
<Text>Average: {calculateAverage(this.props.numbers.map((data) => data['B1'])}</Text>
</View>
);
Reselect is a good option if the calculation is expensive so that it doesn't unnecessarily recalculate the values every render. It's also nicer for testing than having the logic in the component itself.
EDIT: Wow... I'm feeling a bit silly at the moment...
this.props.numbers is not undefined (it's defined by the initial state of the reducer). If you check for length it will render (I've replicated all this code and run it myself to be sure this time).
render() {
if (this.props.numbers.length === 0) {
return null; // or a spinner?
}
const { navigate } = this.props.navigation;
return (
<View>
<Text>####################</Text>
<Text>Intro Screen</Text>
<Text>Number: {this.props.numbers[0]['B1']}</Text>
</View>
);
}
It is important to actually return something (or null) within the if statement so that it doesn't hit the undefined value (this.props.numbers[0]).
Explanation (requested in comments)
It all boils down to the component's lifecycle.
When the component mounts it has an empty array, set by the initialState of the reducer
export default (state = [], action = {}) => {
...
};
The mounting lifecycle methods will fire in order. When the componentDidMount (or componentWillMount depending on which update of the question we are at) the state is replaced in the redux store to have the full data set.
After the mounting lifecycle has completed the react-redux will change trigger the props to change, firing off the updating lifecycle methods.
During this stage render is called again, this time with the correct data.
So the component wont "keep re-rendering until the numbers object is not empty", it will re-render whenever the props change, and if the numbers array is not empty, will include desired components.
Returning null is valid in react and is commonly used to prevent components from trying to access props that are not available yet.