React: Looping through an array within a state - javascript

I am building a component within React. Everything seems to be working perfectly until I tried looping through a state.
Here is my component:
var BidItem = React.createClass({
getInitialState: function() {
return {
theMaxBid: '',
theHighestBids: ''
};
},
componentDidMount: function() {
var $component = this;
$.ajax({
type : "post",
dataType : "json",
url : myAjax.ajaxurl,
data : {action: "get_max_bid"},
})
.done(
function(response){
$component.setState({
theMaxBid: response.max_bid,
theHighestBids: response.highest_bids
});
}
);
},
render: function() {
var dd = [{ids:"2"}, {ids:"5"}];
var cc = this.state.theHighestBids;
console.log(cc);
console.log(dd);
return (
<div>
<p>Max Bid: {this.state.theMaxBid}</p>
</div>
)
}
});
This works, and within the render function both cc and dd output an array that looks like:
When I loop through the cc array (which comes from the state) within the render function:
{cc.map(function(result){
console.log(result);
})}
I get the following error:
Uncaught TypeError: cc.map is not a function
But when I loop through the below dd array, it works:
{dd.map(function(result){
console.log(result);
})}
Why can't I loop the state array?

The function componentDidMount get's ran after the first render call, so the initial render won't have this.state.theHighestBid (tip: highestBid). The first time render is ran this.state.theHighestBid returns '' which doesn't have the #map function.
Change getInitialState's to theHighestBid: [] and it will map through an empty array the first time, then call your AJAX when the component mounts, and then you'll get a response which will populate the state which will render a second time.

Why can't I loop the state array?
Because you don't have an array! theHighestBids: '' creates an empty string.
Change
getInitialState: function() {
return {
theMaxBid: '',
theHighestBids: ''
};
}
To
getInitialState: function() {
return {
theMaxBid: '',
theHighestBids: []
};
}
And make sure response.highest_bid is also an array.

Related

Access variable value in mounted function vuejs

I have a very simple application that initiates a search and filter based on the query parameters. When I initiate the query https://example.com/?filter=2134 it initiates the search and shows me the result of schools. This means that the searchSchools() function is being executed and the results are being fetched.
However, then I execute the filterSuggestions() function, it doesn't seem to apply the filter.
However, when I do a console.log(suggestedSchools) within mounted, it returns empty.
const app = new Vue({
el: '#app',
data: {
suggestedSchools : [],
filter : '',
filteredSchools : [],
},
mounted: function () {
// checking some get parameters and conditions and triggering the search
this.searchSchools(); // function that initiates ajax request and store the results into suggestedSchools
this.filter = 2134; // the postcode value comes from the get request
this.filterSuggestions(); // function that applies the postcode filter to the suggestedSchools list and assign the filtered results to filteredSchools.
},
methods: {
searchSchools() {
axios.get('/search-school').then(response => {
this.suggestedSchools = response.data;
this.filteredSchools = response.data;
})
},
filterSuggestions()
{
this.filteredSchools = this.suggestedSchools.filter(school => {
// filtering logic
}
},
},
});
That's because the searchSchools function makes an asynchronous request so when filterSuggestions function is executed it finds the suggestedSchools array empty. I suggest it should be more like this:
const app = new Vue({
el: '#app',
data: {
suggestedSchools : [],
filter : '',
filteredSchools : [],
},
mounted: function () {
// checking some get parameters and conditions and triggering the search
this.searchSchools(); // function that initiates ajax request and store the results into suggestedSchools
this.filter = 2134; // the postcode value comes from the get request
},
methods: {
searchSchools() {
axios.get('/search-school').then(response => {
this.suggestedSchools = response.data;
this.filteredSchools = response.data;
this.filteredSuggestions()
})
},
filterSuggestions()
{
this.filteredSchools = this.suggestedSchools.filter(school => {
// filtering logic
}
},
},
});

reactJS map function not working as expected

I have a reactJS application where I am trying to dynamically render some data that I read in with a fetch() promise. This is the code of my application:
import React from 'react';
import '../styles/app.css';
//think of react components as functions
class Testpage2 extends React.Component {
constructor(props) {
super(props);
this.state = {
numberOfRecords: 0,
productArray: [{
barcode: '',
name: ''
}]
};
}
componentDidMount() {
let currentComponent = this;
var recordCount = 0;
var tempData = [];
//Make use of the API not the web service.
let url = "http://wmjwwebapi-dev.us-west-2.elasticbeanstalk.com/api/getdata";
const options = { method: 'GET' };
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined)
{
console.log("fetch failed");
}
else
{
//inspect the data that the WebAPI returned
var return_code = myJson[0].return_code;
if (return_code == "Default Return code"){
recordCount = -2;
} else {
tempData = JSON.parse(myJson[0].return_string);
recordCount = tempData.barcode.length;
}
currentComponent.setState(
{
numberOfRecords: recordCount,
productArray: currentComponent.state.productArray.push(
{
name: tempData.name,
barcode: tempData.barcode
})
}
);
}
});
}
render() {
console.log(this.state.productArray);
return (
<div>
{ this.state.productArray.map((prod, index) => <li key={index}>{prod.barcode}</li>)}
</div>
)
}
}
export default Testpage2
and this is the error message that I am getting:
Uncaught (in promise) TypeError: this.state.productArray.map is not a function
at Testpage2.render (testpage2.js:67)
This is the result of the console.log() that I added in the render() function:
I'm not really sure what this error is telling me or how to go about debugging the issue.
Any help is greatly appreciated.
Thank you.
The return type of array.push is the new length of the array aka a number
So you set the state property productArray to a number and then try to call number.map which is not defined
How to fix?
push first and then use that array to set the state
const updatedArray = [...currentComponent.state.productArray]
updatedArray.push({ name: tempData.name, barcode: tempData.barcode })
currentComponent.setState({
numberOfRecords: recordCount,
productArray: updatedArray
}
Resources:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
According to MDN:
The push() method adds one or more elements to the end of an array and returns the new length of the array.
It appears that your code expects that Array.push() will return the modified array itself:
productArray: currentComponent.state.productArray.push(...
To prevent the state corruption you should do construct the new array separately, before invoking setState().
Array's push() function returns integer, so you cannot call map() function on it. Try to change your function to:
currentComponent.setState({
numberOfRecords: recordCount,
productArray: [...currentComponent.state.productArray, {
name: tempData.name,
barcode: tempData.barcode
}]
})
The JavaScript Array.push method does not return the modified array, it returns the new length of the array, which is a number. Numbers in JavaScript do not have the map method.
You need to do first create a clone of the productArray, then push the new data, and finally set state:
const newProductArray = [...currentComponent.state.productArray]
newProductArray.push({
name: tempData.name,
barcode: tempData.barcode
})
currentComponent.setState(
{
numberOfRecords: recordCount,
productArray: newProductArray
}
)
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push

Bind vuejs function as data with context vuejs

I want to use a function as a data property. This seems to work fine as in the case of the 'works' data property. However I need the this context in the function so that I can calculate values stored in the this.shoppingCart (another property).
Is this possible? If so what am I doing wrong?
new Vue({
el: '#vueApp',
data: {
shoppingCart: [],
works : function () {
return "testfunc";
},
totalPriceCalcProperty : function () {
this.totalPrice = this.shoppingCart.reduce(function(total, cartItem){
console.log(total, cartItem);
return total + parseFloat(cartItem.price);
}, 0);
}
},
methods: {
totalPriceCalc: function () {
this.totalPrice = this.shoppingCart.reduce(function(total, cartItem){
console.log(total, cartItem);
return total + parseFloat(cartItem.price);
}, 0);
},
}
You should implement this by using methods, not data.
data is helping you to store something rather than handle some actions.
In methods, you can call this.xxx to get the properties from data or property

How to render unknown/variable number of React elements

I have this React component that looks like this:
var TestResult = React.createFactory(React.createClass({
displayName: 'test-result',
getInitialState: function getInitialState() {
return {
active: false,
testLines: [] //this value will update after AJAX/WebWorker completes
};
},
makeNewState: function makeState(data) {
this.setState(data);
},
componentDidMount: function () {
var self = this;
var testPath = this.props.testPath;
setTimeout(function(){
$.get(testPath).done(function (msg) {
var myWorker = new Worker('/js/workers/one.js');
myWorker.postMessage(msg);
myWorker.onmessage = function (msg) {
self.setState({testLines: msg.data.testLines});
};
}).fail(function (err) {
console.error(err);
});
}, Math.random()*2000);
},
render: function() {
var self = this;
return React.createElement('p', {
className: this.state.active ? 'active' : '',
onClick: this.clickHandler,
},
self.state.testName, ' ', self.state.testLines, React.createElement('b', null, 'Pass/fail')
);
}
}));
what I want is to render a variable number of components in the render function - the variable number is related to number of elements in the testLines array.
So, in order to do that, I might try changing the render method above:
render: function() {
var self = this;
return React.createElement('p', {
className: this.state.active ? 'active' : '',
},
self.state.testName, ' ', React.createElement('div', self.state.testLines, React.createElement('b', null, 'Pass/fail')
);
}
so what I am trying to do is pass testLines, which is an array of React.createElement results, to React.createElement. Is this the correct way of doing it? "It" meaning rendering a variable number of React elements.
What you have to do is map over the array and create each of the sub-elements, then render those:
render: function() {
var lines = this.state.testLines.map(function(line, i) {
// This is just an example - your return will pull information from `line`
// Make sure to always pass a `key` prop when working with dynamic children: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children
return (
<div key={i}>I am a line!</div>
);
});
return (
<div id='lineContainer'>
{lines}
</div>
);
};

ReactJs Passing parameters to parent without event handler

i need to pass parameters from child component to parent without event handler like onClick...
My parent component has a method and child component "A" every x second must pass parameters to parent's method. This methods change parent status and pass this value as props to another child component "B".
How can i do this??
this is my code:
var Parent = React.createClass({
getInitialState: function() {
return {
notification: [ {
data: "-",
message: "no notification to show",
type: "-"
} ]
};
},
handleNotification: function(res) {
var notification = this.state.notification;
notification.push(res);
this.setState({ notification: notification });
},
render: function() {
return(
<div>
<Child callFunction={this.handleNotification} />
<NotificationBox
notification={this.state.notification}
/>
</div>
);
}
});
var Child = React.createClass({
displayName: "Child",
handleReturnNotification: function(o) {
this.props.callFunction.bind(o);
},
render: function() {
var msg = "message:" ;
var o = {
data: "-",
message: msg,
type: "Alert"
};
this.handleReturnNotification.bind(this, o);
return (
<div></div>
);
}
});
Pass the parent method as a props. In child A do this.props.parentMethod(parameter);.
add function in useEffect(); to fire it onLoad
useEffect(() => {
props.callFunction()
}, [someVariable]);

Categories

Resources