Getting Object: "undefined" on React - javascript

I am a newbie in react JS and I am trying to pull data from a url in Json format.
I did the following but I keep on getting a feeback at the console as
Rovers: undefined.
How do I go about it when am supposed to get something like
Rovers:[object, object, object]
class App extends React.Component {
constructor(props){
super(props);
this.state={rovers:[]};
}
componentWillMount(){
api.getRovers().then((response) =>{
this.setState({
rovers: response.rovers
});
});
}
render() {
console.log("Rovers: ", this.state.rovers);
}
and this is where am calling the json link
var api={
getRovers(){
var url='https://jsonplaceholder.typicode.com/posts/1';
return fetch(url).then((response)=> response.json());
}
};
module.exports=api;

The endpoint replies with object that does not include rovers. However, it includes : id, userId, title and body
That's why response.rovers is undefined. Then this.state.rovers is the same
So , you might mean body instead of rovers , in this case , replace:
componentWillMount(){
api.getRovers().then((response) =>{
this.setState({
rovers: response.rovers
});
});
}
By :
componentWillMount(){
api.getRovers().then((response) =>{
this.setState({
rovers: response.body.split('\n')
});
});
}

Related

Get data attribute from html before calling API in React

I'm building a React component to load blog articles to insert inside a CMS.
I will be getting an author name from a data-name attribute from html.
When I run this code with url2 (hard coded name of the author) everything works. When I run the code with url1 (name of author read from data-attribute) nothing works. Please help.
I have this html:
<div id="dataElement" data-name="Peter Smith"></div>
And this is the code inside my react component:
constructor(props) {
super(props);
this.state = {
insightsData: [],
loading: true,
authorName: document.getElementById('dataElement').getAttribute('data-name').replace(/ /g, "_")
}
}
componentDidMount(){
let self = this;
let url2 = '/api/Insights/GetAuthorArticles?authorName=Peter_Smith&numRecords=5';
let url1 = `/api/Insights/GetAuthorArticles?authorName=${this.state.authorName}&numRecords=5`;
this.setState({loading:true});
var Promise = require("es6-promise");
Promise.polyfill();
axios.get(url)
.then((response) => {
self.setState({
insightsData: response.data.InsightsResults.Records
}, this.setState({loading:false}));
console.log(response.data.InsightsResults.Records);
});
}
The html is loaded only after the constructor. Try this, using react ref:
constructor(props) {
super(props);
this.state = {
insightsData: [],
loading: true,
}
}
componentDidMount(){
let self = this;
let url2 = '/api/Insights/GetAuthorArticles?authorName=Peter_Smith&numRecords=5';
let url1 = `/api/Insights/GetAuthorArticles?authorName=${document.getElementById('dataElement').getAttribute('data-name').replace(/ /g, "_")}&numRecords=5`;
this.setState({loading:true});
var Promise = require("es6-promise");
Promise.polyfill();
axios.get(url)
.then((response) => {
self.setState({
insightsData: response.data.InsightsResults.Records
}, this.setState({loading:false}));
console.log(response.data.InsightsResults.Records);
});
}
EDIT: solution without ref.
<div id="dataElement" data-name="Peter Smith"></div> gets mounted after the constructor. you will never have dataElement in the dom when you run authorName: document.getElementById('dataElement')...
try moving authorName: document.getElementById('dataElement')... to componentDidMount using setState and componentDidMount to componentDidUpdate
Here are the docs, if you wanna deep dive. https://reactjs.org/docs/react-component.html#mounting

How to get a data after react select using axios and ReactJS?

I am newbie on ReactJS, I want to get a Price value just after the select of the Product name by react select and display it.
My method :
constructor(props) {
super(props);
this.state = {
PrixV: ""
}
PrixDisplay(selectprdt) {
return axios.get("/app/getPrixprod/" + selectprdt).then(response => {
if (response && response.data) {
this.setState({
PrixV: response.data
});
}
console.log(response.data)
}).catch(error => {
console.error(error);
});
}
I try to read this value by :
<p>{this.state.PrixV} </p>
When I run it, nothing is displayd on the Price column and after I select the product name, I get :
Objects are not valid as a React child (found: object with keys {PrixV}). If you meant to render a collection of children, use an array instead.
in p (at AjouterFacture.js:383)
And the console returns :
[{…}]0: {PrixV: "250.000"}length: 1__proto__: Array(0)
How can I read and display it ?
You must use the map, try to change the code like this :
constructor(props) {
super(props);
this.state = {
Prix: []};
render() {
let {
Prix
} = this.state.Prix;
return (
<td>
{ this.state.Prix.map((pr, k) =>
<p key={k} >{pr.PrixV} </p>
)}
</td>
);}
PrixDisplay(selectprdt) {
return axios.get("/app/getPrixprod/" + selectprdt).then(response => {
if (response && response.data) {
this.setState({
Prix: response.data
});
}
}).catch(error => {
console.error(error);
});
}
I hope that's will be helpful.
constructor(props) {
super(props);
this.state = {
mydata: ''
};
productNameSelected(selectprdt) {//not sure from where you will get selectprdt variable , but something like this will work
axios.get("/app/getPrixprod/" + selectprdt).then(response => {
if (response && response.data) {
this.setState( {mydata : response.data});
}
console.log(response.data)
})
}
<p>{this.state.mydata} </p> //my data should not be a object , so you need to make string if you wnat to directly use it here
Edit
I can see you are able to get the response , but react still gives error:-
change the paragrah code to
<p>{this.state.PrixV[0].PrixV} </p>
Or The good way will be to set the data properly so
let paragrah be same
<p>{this.state.PrixV} </p>
PrixDisplay(selectprdt) {
return axios.get("/app/getPrixprod/" + selectprdt).then(response => {
if (response && response.data && response.data[0]) {
this.setState({
PrixV: response.data[0].PrixV
});
}
console.log(response.data)
}).catch(error => {
console.error(error);
});
}
You are getting the error because currently you are getting PrixV as an array(object) not a primitive data type.
Hope this solves the issue.

Why 'this' is undefined inside a Promise call

I don't understand what's going on
componentDidMount() {
console.log('componentDidMount');
//const self = this;
let _id = this.props.match.params.id.toUpperCase();
if (_id != this.state.id.toUpperCase()) {
axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
.then(response => {
// let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
this.setState({ id: _id }); //this == undefined
});
}
}
I can get a response back but this is always undefined and I'm unable to setState. I'm using an arrow function which I thought was scope 'this' to the component level. I can fix it by making a new var and setting 'this' before I make the request. I know that this should be working though. What am I missing?
My entire component
import React, { Component } from 'react';
import axios from '../../axios';
class CoinViewer extends Component {
state = {
coin: {},
hasLoaded: false,
id: ''
}
componentDidMount() {
console.log('componentDidMount');
//const self = this;
let _id = this.props.match.params.id.toUpperCase();
if (_id != this.state.id.toUpperCase()) {
axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
.then( resp => {
// let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
this.setState({ id: _id });
});
}
}
componentWillMount() {
}
componentWillUpdate() {
}
componentDidUpdate() {
}
getCompleteCoinData(_id) {
}
render() {
return (
<div>
CoinViewer Component: {this.state.id} sads
</div>
)
}
}
export default CoinViewer
Solution 1: arrow functions..
requestSuccess = (resp) => {
// let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
this.setState({ id: _id });
}
componentDidMount() {
console.log('componentDidMount');
//const self = this;
let _id = this.props.match.params.id.toUpperCase();
if (_id != this.state.id.toUpperCase()) {
axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
.then(this.requestSuccess);
}
}
Solution 2: binding
componentDidMount() {
console.log('componentDidMount');
//const self = this;
let _id = this.props.match.params.id.toUpperCase();
if (_id != this.state.id.toUpperCase()) {
axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
.then((resp) => {
// let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
this.setState({ id: _id });
}.bind(this));
}
}
:Edit
Wow, the below is kinda true, but the real issue is you didn't initialize state. https://reactjs.org/docs/react-component.html#constructor
constructor() {
super();
this.state = {
coin: {},
hasLoaded: false,
id: ''
}
}
You could use lexical scoping and fix like this, this is a popular pattern to protect this.
Basically, when you use promises or functions from other libraries/ APIs you do not know what they have set their context inside the callback functions to.
In order to use the context you want, you keep the context you need saved in a variable within scope and reference it there _this, rather than by pointing to the context this. I'd recommend reading 'you dont know js' to understand this concept further.
componentDidMount() {
console.log('componentDidMount');
const _this = this;
let _id = _this.props.match.params.id.toUpperCase();
if ( _id != _this.state.id.toUpperCase() ) {
axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
.then(response => {
_this.setState({ id: _id }); //this == undefined
});
}
}
When working with React.js, chances are you have faced a problem how
to access this from inside the promise.There is more than one solution to resolve this reference inside the
promise. The old approach would be setting the self = this
reference While this would work, the recommended solution, which is
more inline with ES6, would be to use an arrow function here:
class Component extends React.Component {
componentDidMount() {
let component = this;
axios.get('http://…').then(function(data) {
component.setState( { name: data.blah } );
});
}
}
The arrow syntax, as stated above, is a much smarter way to allow use
of this to make reference to React.Component classes, as we can see
below:
class Component extends React.Component {
componentDidMount() {
axios.get('http://…').then(data => {
this.setState( { name: data.blah } );
});
}
}
Please note, instead of using
function(data) { //body },
we used data => { //body }, and in this case this reference won’t get the promise instance back.

Cant pass a function to a React child from parent (through a list)

Im trying to pass a simple list from a parent to a set of child components and i cant pass down a function. i have something line for line that is the exact same bloody thing that works but this does not.
Does anyone see what is going wrong?
This is the function in the parent that i cant reach (the console.log is not firing):
setClassImage(name, image){
console.log('inside setClassImage');
var TitleArray = this.state.TitleArray;
TitleArray[0] = name;
var ImageArray = this.state.ImageArray;
ImageArray[0] = image;
this.setState({
characterModal: false,
equipmentModal: false,
TitleArray: TitleArray,
ImageArray: ImageArray
});
}
Setting the list in the parent:
let listClasses;
if(this.state.classResults.length!=0){
listClasses = this.state.classResults.map((item,i) => {
return (
<ListClass key={i} classes={item} setClassImage={this.setClassImage.bind(this)}/>
);
});
}
in the render of the parent:
<SelectorBox>
<ListBox>
{listClasses}
<br/>
</ListBox>
<SelectorButton onClick={(e)=>this.cancelChange(e)}>No Class</SelectorButton>
</SelectorBox>
In the child:
class ListClass extends Component{
constructor(props){
super(props);
this.state={
}
}
getImage(e){
e.preventDefault();
var self = this;
axios.post('http://localhost:5000/post2/characterimage', {
search: this.props.classes,
})
.then((response)=>{
console.log('response from the pixabay call ', response.data);
self.props.setClassImage(self.props.classes, response.data);
})
.catch(()=>{
console.log('hello axios error');
});
}
render(){
return(
<div>
<ItemContainer onClick={(e)=>this.getImage(e)}>
<p>
{this.props.classes}
</p>
</ItemContainer>
</div>
)
}
}
I can see console.log('response from the pixabay call ', response.data); and it fires correctly from data on the backend. But the function is not called! The weirdly named containers are purely for styling, so just assume they all act like divs.
The arrow function in your .then() call will automatically bind this to the proper context, so you don't need to do the var self = this; However you do need to bind your getImage function in your constructor. OR
Update your function definition to:
....
getImage = (e) => {
e.preventDefault();
axios.post('http://localhost:5000/post2/characterimage', {
search: this.props.classes,
})
.then((response) => {
console.log('response from the pixabay call ', response.data);
this.props.setClassImage(this.props.classes, response.data);
})
.catch(()=>{
console.log('hello axios error');
});
}
....
}
Otherwise, bind getImage in your constructor:
constructor(props){
super(props);
this.state = {};
this.getImage = this.getImage.bind(this);
}

Stream the contents of each file using web sockets and ReactJs

I am trying to read files of a directory and usin socket i have to render the file name and file data using React.
here is what i have done:
Server :
var files = fs.readdirSync(currentPath);
for (var i in files) {
(function(j){
var currentFile = currentPath + '/' + files[j];
var fileName = files[j];
var stats = fs.statSync(currentFile);
if (stats.isFile()) {
fs.readFile(currentFile, function (err, data) {
if (err)
throw err;
if (data){
var fileAndData=currentFile+" "+data.toString('utf8')
io.emit('file data',fileAndData);
console.log("file name and file data ***",currentFile+data.toString('utf8'));
}
});
}
else if (stats.isDirectory()) {
traverseFileSystem(currentFile);
}
}
)( i );
}
client :
parent component :
class FileData extends Component{
constructor(props) {
super(props);
this.state = {
filedata:null,
filename:null,
data:[]
}
}
componentDidMount() {
socket.on('file data', function(msg){
this.state.data.push(msg);
// this.setState({filename:msg})
}.bind(this));
}
render(){
return(<div>
<DataCard data={this.state.data}/>
</div>);
}
}
ReactDOM.render(
<FileData/>,document.getElementById('messages')
);
client : child component
constructor(props) {
super(props);
this.state={data:this.props.data}
}
render(){
console.log("array",Array.isArray(this.state.data))
console.log("array length",this.state.data.length)
console.log("array is ==>",this.state.data)
return(
<MuiThemeProvider>
</MuiThemeProvider>);
}
I want display the data and file name and file data using map.But when i am consoling the data recieved in child component Array length is Zero. Here is the
console result :
array true
array length 0
array is ==> Array[0]0: "/vagrant/assignment/server/data//file 1.txt hello from file 1."1: "/vagrant/assignment/server/data//file 2.txt hello from file 2."length: 2__proto__: Array[0]
Why 3rd console showing 2 data if its length is zero.
You can't mutate the state by doing this.state.data.push(msg);
Try
var data = this.state.data;
data.push(msg);
this.setState({data: data});

Categories