How do you convert an object to an array in js ? (or is there a better way to dynamically update a nested object)
Basically I'm trying to update some data for the plotly component from an axios request on the fly, but plotly complains it is fed an object instead of an array.
Part of the code :
var trace0 = {
type: 'ohlc',
xaxis: 'x',
yaxis: 'y',
increasing: {line: {color: 'green'}},
decreasing: {line: {color: 'red'}},
line: {color: 'rgba(31,119,180,1)'},
x: ['2017-01-17'],
open: [118.339996],
high: [120.239998],
low: [118.220001],
close: [120],
};
var init_data = [trace0];
export default class GraphRAW extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
layout: {},
config: {},
checking:false,
revision: 0
};
}
getStart = () => {
const symbol = 'tst'
return axios
.post(API_URL + "startRAW", {symbol } )
.then((response) => {
if (response.data) {
var newData = Object.assign({}, this.state.data);
newData[0].x = response.data.x;
newData[0].close = response.data.close;
newData[0].open = response.data.open;
newData[0].low = response.data.low;
newData[0].high = response.data.high;
console.log('new data here =>');
console.log(newData); // Data seems ok in console
console.log(typeof(newData)); // Typeof new data is object
this.setState({data: newData });
this.setState({revision: this.state.revision++}); // Update revision to initiate a new plot in the plotly component
console.log('this data here =>');
console.log(this.data); // Undefined in console
console.log(typeof(this.data)); // Undefined in console
return response;
}
});
componentDidMount(){
this.setState({config: init_config});
this.setState({layout: init_layout});
this.setState({data: init_data});
this.getStart();
}
Warning: Failed prop type: Invalid prop data of type object supplied to PlotlyComponent, expected an array.
It seems response.data.x (~.close ~.open ~.low ~.high) are objects which need to be converted to an array in the data object.
In the render :
<Plot useResizeHandler data={this.state.data} layout={this.state.layout} config={this.state.config} revision={this.state.revision} style={{width: "100%" }} />
Any help highly appreciated
Posting my comment as an answer:
You just need to wrap the values returned from the server in an array, e.g:
newData[0].x = [response.data.x];
Related
I'm using axios to get data from an endpoint. I'm trying to store this data inside the state of my React component, but I keep getting this error:
Error: Results(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
I've struggled with many approaches: arrow functions etc., but without luck.
export default class Map extends Component {
constructor() {
super();
this.state = {
fillColor: {},
selectedCounty: "",
dbResponse: null,
};
}
getCounty(e) {
axios.get("/getWeatherData?county=" + e.target.id)
.then((response) => {
this.setState(prevState => {
let fillColor = {...prevState.fillColor};
fillColor[prevState.selectedCounty] = '#81AC8B';
fillColor[e.target.id] = '#425957';
const selectedCounty = e.target.id;
const dbResponse = response.data;
return { dbResponse, selectedCounty, fillColor };
})
}).catch((error) => {
console.log('Could not connect to the backend');
console.log(error)
});
}
render() {
return (
<div id="map">
<svg>big svg file</svg>
{this.state.selectedCounty ? <Results/> : null}
</div>
)
}
I need to set the state using prevState in order to update the fillColor dictionary.
Should this be expected? Is there a workaround?
I'm implementing a calendar in react native with expo, the problem is that when I want to bring a date from the firebase database to paint it in calendar, it repeats several times, here a picture
View picture
The code is this:
constructor(props) {
super(props);
this.state = {
selected: "",
usuarios: [],
};
}
componentDidMount() {
firebase
.database()
.ref("DatosCli/")
.on("child_added", (data) => {
var datos = data.val();
var usuariosTemp = this.state.usuarios;
datos.key = data.key;
usuariosTemp.push(datos);
this.setState({ usuarios: usuariosTemp });
});
}
cargarDatos = async () => {
var userTemp = new Array();
var data = await firebase.database().ref("/DatosCli").once("value");
data.forEach((child) => {
var user = child.val();
user.key = child.key;
userTemp.push(user);
});
this.setState({ usuarios: userTemp });
};
render() {
return (
<View style={styles.container}>
{this.state.usuarios.map((usuarioTemp) => (
<CalendarList
markedDates={{
[usuarioTemp.date]: {
selected: true,
disableTouchEvent: true,
selectedColor: "orange",
selectedTextColor: "red",
},
}}
/>
))}
</View>
);
}
}
I know that having the map() outside of CalendarList is the reason why it repeats itself several times, how would this be solved then?
The calendar library that i use is: https://github.com/wix/react-native-calendars
You want to have a list of marked dates and not a list of CalendarList components. Right now you are looping through the dates and create a new CalendarList for each of your dates. Instead you want to create an object of dates. Map is part of the array protoype. The prop markedDate seems to require an object though. For that, we need to refactor your code a bit and replace map by forEach for example to construct the object.
Let's split this problem up into two steps. First we create the object of markedDates by using the forEach function and after that we pass it as a prop to CalendarList.
render() {
const markedDates = {};
this.state.usuarios.forEach((usuarioTemp) => {
markedDates[usuarioTemp.date] = {
selected: true,
disableTouchEvent: true,
selectedColor: "orange",
selectedTextColor: "red",
};
};
return (
<View style={styles.container}>
<CalendarList markedDates={markedDates} />
</View>
);
}
So ideally my parent component is mapping through a database and rendering them based on the user's choice. Right now right now the information is being passed correctly and the app is rendering what I need it too (the card component) in the correct amount however it is full of dummy info. (Someone clicks beer, there are three beer types in the database, the app renders three card components full of dummy info).
Here is the parent component:
class Render extends React.Component {
constructor(props) {
super(props);
console.log("Here are your props", props);
}
componentDidMount() {
let options = {
method: 'GET',
url: 'http://localhost:8080/drinks',
};
let drinks = [];
console.log("this is",this);
axios.request(options)
.then( (response) => {
console.log(response);
this.setState({ drinks: response.data })
})
.catch(function (error) {
console.log(error);
});
}
render() {
console.log("this.state is",[this.state])
let stateArray = [this.state]
if (stateArray[0] == null) {
console.log("returning with nothing")
return <div></div>
}
let firstElement = stateArray[0];
let drinks = firstElement.drinks;
let drinkChoice = this.props.reduxState.drinkChoice
console.log("drinkchoice is here" , drinkChoice)
// const props = this.props
console.log("just drinks", drinks)
let drinkInfo = {
type: this.state.drinks.type,
name: this.state.drinks.name,
manufacturer: this.state.drinks.manufacturer,
rating: this.state.drinks.rating,
date: this.state.drinks.date,
description: this.state.drinks.description,
favorite: this.state.drinks.favorite
}
let cardComponents = drinks.map((drink) =>{
if (drink.type === drinkChoice) {
return (<InfoCard props={this.state.drinks} />)
} else {
return <div>Nothing to Report</div>
}})
return (
<div>
<div>{cardComponents}</div>
</div>
)
}
}
export default Render
Now I need it to render the actual database information for each entry. In the child/cardcomponent- I can console.log the props and it will correctly show the right information. It's getting through. But anytime I try to be more specific ( props.name ) it turns to undefined.
I have been at this for days and i'm so confused. The information is right there! I just need to grab it!
Here is the code for the child/card component:
const useStyles = makeStyles(theme => ({
root: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: 'rotate(180deg)',
},
avatar: {
backgroundColor: red[500],
},
}));
export default function InfoCard(props) {
const classes = useStyles();
if( props.length <= 0 ) {
return (<div></div>);
} else {
console.log("props are here")
console.log( props )
console.log("props dot name")
console.log ( props.name )
}
props.each(function (drink) {
console.log(drink.name);
});
return (
<Card className={classes.root}>
title = { props.name }
</Card>
);
}
Where have I gone wrong? I feel like i've tried every possible iteration of console.log and drink.name. I'm at the end of my rope.
Thanks for any and all guidance.
sccreengrab of console log
What you're seeing in your log of props is an array of objects. Those objects have names, but the array itself does not, so when you console.log(props.name) it doesn't work and you see undefined. If you try console.log(props[0].name), for instance, you should see a name.
But what's strange here is that props should NOT be an array: it should be an object (whose keys map to the JSX element's attributes). For instance:
<InfoCard name="Bob"/>
would create a props object of:
{name: 'Bob'}
But when you log your props, you see an array, and that means you've somehow/somewhere replaced the actual props object with an array. Without seeing the code where you actually create <Infocard>, I can't speak to the details.
P.S. It might be possible to do this if you did something like:
`<MyComponent {...[{ name: 'Bob']} />`
... but honestly I'm not sure if that even works, and it seems like a bad idea even if it does.
I am just starting to learn reactjs and one of my first use cases is creating a button where depending if user clicks on/off I will make a fetch call and pass this information into one of the variables.I want to eliminate having a function for each type of button. So I figured I could just pass in the value as a prop and use that for the fetch call. You will see this when I try to pass in "this.props.statusnumber".
Unfortunately I get the following error;
Parsing error: this is a reserved word...
Here is my code, any help would be greatly appreciated since I cant find anything online.
import React from 'react';
const API = 'https://use1-wap.tplinkcloud.com/?token=HIDDEN';
let opts = {"method":"passthrough", "set_dev_alias":{"alias":"supercool plug"}, "params": {"deviceId": "HIDDEN", "requestData": "{\"system\": {\"set_relay_state\":{\"state\":0}}}" }};
let headerInfo = {'Content-Type': 'application/json','Version':'1','q': '0.01'};
let statusnumber = {};
export class Name extends React.Component {
constructor(props) {
super(props);
this.state = {
position: "off",
object: [],
};
this.switchStatus = this.switchStatus.bind(this);
this.statusnumber = this.statusnumber.bind(this);
}
switchStatus() {
opts.params.requestData = "{\"system\":{\"set_relay_state\ {\"state\":"+{this.props.statusnumber}+"}}}";
let positionStatus = (this.props.statusnumber === 0) ? "off" : "on";
console.log(this.props.statusnumber);
fetch(API, {
method : 'POST',
headers: headerInfo,
body : JSON.stringify(opts)
})
.then(response => response.json())
.then(data => this.setState({ object: data.object, position: positionStatus}))
};
render() {
const { object } = this.state;
return (
<div>
<button onClick={this.switchStatus} statusnumber={1}>On</button>
<button onClick={this.switchStatus} statusnumber={0}>Off</button>
<p>Current position: {this.state.position}</p>
<p>testing function</p>
</div>
);
}
}
I have an array that is generated from a firebase database query.
I want to save that in state so that as the data changes, it will re-render the screen.
I can't seem to get the value from state into my function. If I put the value from the array, it works, but then it won't automatically re-render when data changes.
Screen shot of it using the array... note the console log is printing that the state is set correctly.
and here it is with the error
It's gotta be right around line 101, but I cannot figure out the right syntax to make thsi work.
UPDATE: I was not initializing state, that was one part of the error.
import React, { Component } from 'react';
import Flexbox from 'flexbox-react';
import firebaseApp from '../api/firebase';
import GeoFire from 'geofire';
var geoRef = firebaseApp.database().ref('shiftgeo');
var geoFire = new GeoFire(geoRef);
var ref = geoFire.ref(); // ref === firebaseRef
var shiftKeys = []; // this array will hold the keys from the geoFire results
var shifts = []; // this array will hold the actual shift data of shifts in the geo, then we will filter it later
console.log(firebaseApp);
export class App extends React.Component {
constructor() {
super();
this.state = {
fname: 'Chris',
lname: 'Chong',
cellphone: '503 830 4313',
email: 'chris#ehotleads.com',
dataSource: ''
};
}
componentWillMount() {
let email = 'chris#ehotleads.com';
let password = '123456789';
firebaseApp.auth().signInWithEmailAndPassword(email, password)
.then((data) => {
//this.setState({ error: 'Account already exists. Logging you in...', loading: false });
console.log('success data', data);
this.setState({
user: data,
});
})
.catch((data) => {
//this.setState({ error: 'Authentication failed.', loading: false });
console.log('error data', data);
});
}
componentDidMount() {
var geoQuery = geoFire.query({
center: [45.616422, -122.580453],
radius: 1000,
});
geoQuery.on("key_entered", function(key, location, distance) {
// dont forget that as shifts are added that match the geo, this will automatically add to the shiftKeys array
//shiftKeys = [];
shiftKeys.push(key)
console.log("Found shift " + key + " at " + location + " (" + distance + " km away)");
});
geoQuery.on("ready", () => {
shifts = []; // we need to blow out the array every time this function runs or it will throw errors
shiftKeys.forEach((shiftKey) => {
//console.log(shiftKey);
let shiftsRef = firebaseApp.database().ref('shifts').child(shiftKey);
shiftsRef.on("value", (snapshot) => {
//console.log(snapshot.val())
//if (snapshot.val().state == "WA" && (snapshot.val().licenseRequired == "CNA" || snapshot.val().licenseRequired == "RN")) {
//if (snapshot.val().licenseType == this.state.licenseType || snapshot.val().licenseRequired == "TEST") {
shifts.push({
key: snapshot.key,
fname: snapshot.val().fname,
lname: snapshot.val().lname,
company: snapshot.val().company,
address1: snapshot.val().address1,
address2: snapshot.val().address2,
city: snapshot.val().city,
state: snapshot.val().state,
zip: snapshot.val().zip,
shiftDate: snapshot.val().shiftDate,
shiftStart: snapshot.val().shiftStart,
shiftLength: snapshot.val().shiftLength,
shiftDescription: snapshot.val().shiftDescription,
licenseType: snapshot.val().licenseType,
logo: snapshot.val().logo,
building: snapshot.val().building,
}) // end shifts.push
var date_sort_asc = function (date1, date2) {
if (date1.shiftDate > date2.shiftDate) return 1;
if (date1.shiftDate < date2.shiftDate) return -1;
return 0;
};
//}
//console.log(this.state.distancePref)
this.setState({
dataSource: shifts,
resultCount: shifts.length,
})
}); // end shiftsRef.on
}); // end shiftKeys map
}); // end geoQuery.on
console.log('ShiftArray: ', shifts)
console.log('StateArray: ', this.state.dataSource)
}
render() {
const listItems = this.state.dataSource.map((shift) =>
<li key={shift.key}>
{shift.address1}
</li>
);
console.log('ShiftArray: ', shifts)
console.log('StateArray: ', this.state.dataSource)
return (
<Flexbox flexDirection="column" minHeight="100vh">
<Flexbox element="header" height="60px">
Header link one
</Flexbox>
<Flexbox flexGrow={1}>
<Flexbox
width="20%"
minWidth="200px"
maxWidth="300px"
style={{ backgroundColor: '#ba0000' }}>
Sidebar Menu Goes Here
</Flexbox>
<Flexbox width="80%" flexDirection="row" style={{ backgroundColor: '#FFF' }}>
<div>List of Shifts Addresses</div>
<ul>{listItems}</ul>
</Flexbox>
</Flexbox>
<Flexbox element="footer" height="60px">
Footer
</Flexbox>
</Flexbox>
);
}
}
Now Im getting Uncaught TypeError: this.state.dataSource.map is not a function
The problem was that I failed to initialize dataSource in the state, and then after that, I initialized it with a string instead of an empty array.
Was missing: dataSource: [] in this.setstate in the constructor.