I have a problem with the react.js code below, the services performs the loading of an array of values what interests me at this moment is the first value of the array inside the component, if I display the first CodArt value before configuring the setState (so if I view the console.log) the value is printed when I view it through the setState tells me that it is not set.
Services.js :
const axios = require('axios').default;
export async function caricamentoarticoliutilizzati() {
var listaarticoli=[];
await axios.post(server.url+'/articolo/statistiche', {})
.then(function (response) {
let data = response.data;
for (let index in data){
var datatemp={
CodMarca : data[index].CodMarca,
CodArt : data[index].CodArt,
Totale : data[index].Totale
};
listaarticoli.push(datatemp);
}
}).catch(function (error) {
console.log("Errore: "+error);
});
return listaarticoli;
}
Main.js:
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
graph: null,
checkedArr: [false, false, false],
totalePreventiviInseriti: 0,
percentualeAccettati:0,
percentualeRifutati:0,
percentualeInCorso:0,
percentualeCantieriChiusi:0,
percentualeCantieriInCorso:0,
percentualeCantieriContoInviato:0,
percentualeCantieriBolle:0,
articoliUtilizzati:[],
};
this.checkTable = this.checkTable.bind(this);
}
async componentDidMount() {
var totalePreventiviInseriti= await getStatistichePreventivi();
var percentualeAccettati=await getStatistichePreventiviAccettati();
var percentualeRifutati=await getStatistichePreventiviRifiutati();
var percentualeInCorso=await getStatistichePreventiviInCorso();
var cantieriPercentualiChiusi=await getStatisticheCantieri("Chiuso");
var cantieriPercentualiInCorso=await getStatisticheCantieri("InCorso");
var percentualeCantieriContoInviato=await getStatisticheCantieri("Conto Inviato");
var percentualeCantieriBolle=await getStatisticheCantieri("Lavoro terminato inserire bolle ");
var articoliUtilizzati=await caricamentoarticoliutilizzati();
console.log("articoliUtilizzati: "+ articoliUtilizzati[0].CodArt.toString());
//Inserimento valori nello stato
this.setState({ totalePreventiviInseriti: totalePreventiviInseriti });
this.setState({ percentualeAccettati: percentualeAccettati });
this.setState({ percentualeRifutati: percentualeRifutati });
this.setState({percentualeInCorso: percentualeInCorso});
this.setState({percentualeCantieriChiusi: cantieriPercentualiChiusi});
this.setState({percentualeCantieriInCorso: cantieriPercentualiInCorso});
this.setState({percentualeCantieriContoInviato: percentualeCantieriContoInviato});
this.setState({percentualeCantieriBolle: percentualeCantieriBolle});
this.setState({articoliUtilizzati: articoliUtilizzati});
}
render(){
....
<p> this.state.articoliUtilizzati[0].CodArt //-->CodArt not set
}
that is because the call to caricamentoarticoliutilizzati return a promise not the array listaarticoli. so in componenetDidMount the variable articoliUtilizzati holds a promise object you can confirm this by:
var articoliUtilizzati=await caricamentoarticoliutilizzati();
console.log("articoliUtilizzati: "+ articoliUtilizzati.then(arr =>arr[0].CodArt.toString()));
Related
I have a parent class Weather, which shows the weather for 4 days. I have a child class, which gets an array of cities. And he should show the the weather for 4 days for a random city in this array. But I have an error - this.makeRandom(...).then is not a function. What is wrong?
class GetRandomCity extends Weather {
constructor(city) {
super();
this.city = city;
}
makeRandom() {
//code
};
init() {
this.makeRandom().then(city => {
this.getCoordinates(city)
}).then(coords => {
return this.getWeatherForecast(coords);
}).then((forecast) => {
const { currently, daily } = forecast;
this.renderForecastInfo(currently, daily);
});
}
}
const w1 = new GetRandomCity(['Paris', 'Minsk', 'Madrid', 'Chikago']);
The reason is because makeRandom does not return a promise. You need to put a return statement before getCoordinates if you choose to make it an async function. Else, you could change your code in your init function to this and it should work:
const city = this.makeRandom();
this.getCoordinates(city).then(coords => {
return this.getWeatherForecast(coords);
}).then(forecast => {
const { currently, daily } = forecast;
this.renderForecastInfo(currently, daily);
});
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.
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);
}
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});
I am building a React app using altjs as my Flux implementation. When I try to create/delete an item from the front end, no matter what I pass as a parameter to the create/delete function, it always ends up as passing the entire state.
For example : I'm trying to delete an item with id=1. I click delete on that item and pass just the id to the delete function in the component. That function calls the delete service again passing the id. Once that gets to the store layer, it has the entire state of the component and not just the id that is passed.
I'm still fairly new to React/Flux and not sure what I'm doing wrong or why this is happening.
Main component delete function :
deleteItem = (id) => {
console.log(id) //logs out 56b36c34ad9c927508c9d14f
QuestionStore.deleteQuestion(id);
}
At this point id is still just the id.
QuestionStore :
import alt from '../core/alt';
import QuestionActions from '../actions/QuestionActions';
import QuestionSource from '../sources/QuestionSource';
class QuestionStore {
constructor() {
this.bindActions(QuestionActions);
this.exportAsync(QuestionSource);
this.loaded = false;
this.modalIsOpen = false;
this.data = [];
this.question = {
"text": '',
"tag": [],
"answer": [],
"company": [],
"createdAt": ''
};
this.error = null;
this.questionAdded = null;
this.questionDeleted = null;
}
onGetQuestions(data) {
if (data === false) {
this.onFailed();
} else {
this.data = data;
this.loaded = true;
}
}
onCreateQuestion(response) {
if (response === false) {
this.onFailed();
} else {
this.questionAdded = response;
}
}
onDeleteQuestion(response) {
if (response === false) {
this.onFailed();
} else {
this.questionDeleted = response;
}
}
onFailed(err) {
this.loaded = true;
this.error = "Data unavailable";
}
}
export default alt.createStore(QuestionStore, 'QuestionStore');
QuestionSource :
import Api from '../services/QuestionApi';
import QuestionActions from '../actions/QuestionActions';
let QuestionSource = {
fetchData() {
return {
async remote(state) {
return Api.getQuestions()
},
success: QuestionActions.getQuestions
}
},
createQuestion(question) {
return {
async remote(question) {
return Api.createQuestion(question)
},
success: QuestionActions.createQuestion
}
},
deleteQuestion(id) {
//id here is an object of the entire state of QuestionStore
return {
async remote(id) {
return Api.deleteQuestion(id)
},
success: QuestionActions.deleteQuestion
}
}
};
export default QuestionSource;
Once it hits this point, id is now the entire state of the component even though only the id is passed.
The first parameter that is bound to the action is the state of the store (part of the result of the exportAsync call. So all parameters shift one to the right, and the first parameter you call the function with in turn becomes the second parameter. See below code example:
deleteQuestion(state, id) {
//state here is an object of the entire state of QuestionStore
//id will be the first argument you provide to the function.
return {
async remote(id) {
return Api.deleteQuestion(id)
},
success: QuestionActions.deleteQuestion
}
}
Documentation from alt.js about handling async operations.