setState is not working properly in react native - javascript

i want to create a object with multiple object. the data is something like this
dataList = [{inputFieldId: 1, dataField:{...}, data: '120'}, {inputFieldId: 2, dataField:{...}, data: '120'} ]
what is want like this.
res = [{1: '120'}, {2: '120'}]
i write a code for this but its giving me the last object data only.
constructor(){
super()
this.state = {
inputValue:{},
datalist = [],
}
}
async componentWillMount(){
for(var key in dataList){
this.setState({
inputValue: {
...this.state.inputValue,
[dataList[key].inputFieldId]: dataList[key].data
}
})
}
}
code output = { 2: '120'}

You can try a code as follows:
constructor(){
super()
this.state = {
inputValue: {},
datalist = [],
}
}
async componentWillMount() {
const inputValues = [];
for(var key in dataList) {
inputValues.push({[dataList[key].inputFieldId]: dataList[key].data});
}
this.setState({ inputValue: inputValues });
}

Related

setState() in Reactjs updating multiple properties instead of one

When I update 'classProficienciesChoices' in my state using setState() it is updating not only that property, but also where I derived the 'classProficienciesChoices' info from in the 'classSelected' property, AND ALSO from where I derived the classSelected info from in the 'classesInfo' property.
The same function I update 'classProficienciesChoices' I also update 'classProficiencies', and it updates properly in the one property I tell it to, and not the elements where the information was derived from.
Any insight would be helpful. The Create component has other components nested and none of them have state and only use props passed. There are navigation, selection, and information display components nested.
import React, { Component } from 'react'
import Create from './Create'
class App extends Component {
constructor(props) {
super(props);
const url = 'http://www.dnd5eapi.co/api/';
fetch(url + 'classes')
.then(result => result.json())
.then(result => { this.setState({ classes: result, }, this.getInfo(result)) });
}
state = {
classes: {}, //assigned value from API call in constructor
classesInfo: [], //assigned value from API call in getInfo()
classSelected: {}, //assigned a value derived from classInfo in displayClassInfo()
classProficiencies: [], //assigned a value derived from classSelected in setStartingProficiencies()
classProficienciesChoices: [], //assigned a value derived from classSelected in setStartingProficiencies()
}
getInfo(data) {
let info = []
const url = 'http://www.dnd5eapi.co'
for (var i = 0; i < data.results.length; i++) {
fetch(url + data.results[i].url)
.then(result => result.json())
.then(result => info.push(result))
}
this.setState({ classesInfo: info, })
}
}
setStartingProficiencies(chosenClass) {
const profs = chosenClass.proficiencies.map((prof) => {
return prof;
});
const proChoice = chosenClass.proficiency_choices.map((choices) => {
return choices;
});
this.setState({ classProficiencies: profs, classProficienciesChoices: proChoice, });
}
addProficiency = (proficiencyName) => {
const { classProficienciesChoices } = this.state
// classProficienciesChoices: [
// { choose: 2, type: 'proficiencies', from: [{ name: 'someName', url: 'someUrl' }, { name: 'someName', url: 'someUrl' }] },
// ]
// different classes have more objects in the parent array
let newChoiceArray = classProficienciesChoices.map((choices) => {
return choices
})
for (var i = 0; i < newChoiceArray.length; i++) {
for (var j = 0; j < newChoiceArray[i].from.length; j++) {
if (newChoiceArray[i].from[j].name === proficiencyName) {
let newChoices = newChoiceArray[i].from.filter(function (proficiency) { return proficiency.name !== pIndex })
let newProficiency = newChoiceArray[i].from.filter(function (proficiency) { return proficiency.name === pIndex })
newChoiceArray[i].from = newChoices //I think this is the problem
this.setState(state => ({
classProficiencies: [...state.classProficiencies, newProficiency[0]],
proficienciesChoices: newChoiceArray,
}))
}
}
}
}
displayClassInfo = index => {
const { classesInfo } = this.state
for (let i = 0; i < classesInfo.length; i++) {
if (classesInfo[i].index === index) {
const classSelected = classesInfo.filter(function (cClass) { return cClass.name === classesInfo[i].name })
this.setState({ classSelected: classSelected[0], isClassSelected: true }, this.setStartingProficiencies(classSelected[0]),)
break;
}
}
}
render() {
const { classes, classesInfo, classSelected, isClassSelected, classProficiencies, classProficienciesChoices } = this.state
return (<Create classes={classes} classesInfo={classesInfo} displayClassInfo={this.displayClassInfo} classSelected={classSelected} isClassSelected={isClassSelected} category='classes' classProficiencies={classProficiencies} classProficienciesChoices={classProficienciesChoices} addProficiency={this.addProficiency} />);
}
}
export default App
You call setState four times, of course it will update the state multiple times.
SOLVED!!! Stumbled across turning the array into a string and then back. It breaks the reference and creates an entirely new array. Reference type got me.
setStartingProficiencies(chosenClass) {
const proficiencies = JSON.parse(JSON.stringify(chosenClass.proficiencies))
const proficienciesChoices = JSON.parse(JSON.stringify(chosenClass.proficiency_choices))
this.setState({ classProficiencies: proficiencies, classProficienciesChoices: proficienciesChoices, });
}

How to sum the value only once in react redux

I would like to know in my scenario: After receiving props, the function gets called in the compoentdidupdate method, in which am summing up the amount if id is same, But it keeps on adding the values multiple times on load. how to resolve this.
class Data extends React.PureComponent{
constructor(props){
super(props);
this.state={
total: "";
}
}
componentDidMount() {
this.callFetch();
}
callFetch(){
this.props.dispatch(getData("all"));
this.props.dispatch(newData("new"));
}
componentDidUpdate(){
const { alldata, newdata } = this.props.query;
const obj =[...alldata, ...newdata];
const result=[];
if(obj.length > 0) {
obj.forEach(function (o) {
var existing = result.filter(function (i) { return i.id=== o.id})[0];
if (!existing)
result.push(o);
else
existing.amount+= o.amount;
});
this.setState({total: result})
}
}
render(){
return(
this.state.total.length > 0 ?
this.state.total.map(e=>{
<div>price:{e.amount}</div>
}) : ""
)
}
props am receiving is below, but in output am receiving 1200, and keeps on increasing,
alldata= [{
id: 1,
amount: 200
}, {
id: 2,
amount: 400
}]
newdata= [{
id: "1",
amount: 400
}]
expected output:
price: 600
price: 400
Hey #miyavv Have a look at the below piece of code. Comparing prevProps and current props should help. It is general technique used in reactjs to solve non-needed runs in componentDidUpdate.
class Data extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
total: ""
};
}
componentDidMount() {
this.callFetch();
}
callFetch() {
this.props.dispatch(getData("all"));
this.props.dispatch(newData("new"));
}
componentDidUpdate(prevProps) {
const { alldata, newdata } = this.props.query;
const obj = [...alldata, ...newdata];
const result = [];
// new Line added
const { alldata: prevAllData, newdata: prevNewData } = prevProps.query;
if (prevAllData !== alldata || prevNewData !== newdata) {
if (obj.length > 0) {
obj.forEach(function(o) {
var existing = result.filter(function(i) {
return i.id === o.id;
})[0];
if (!existing) result.push(o);
else existing.amount += o.amount;
});
this.setState({ total: result });
}
}
}
render() {
return this.state.total.length > 0
? this.state.total.map(e => {
<div>price:{e.amount}</div>;
})
: "";
}
}
Let me know if it helps !!. Thanks
That’s because you are dispatching two actions which will result to call componentDidUpdate multiple times. And in your componentDidUpdate method there’s no conditioning telling that your data is already fetched.
You could call only one action that will further dispatch two actions you are dispatching in callFetch method. You could also keep a flag which will tell whether the data is yet fetched or not.
If you are using redux-thunk, than it can be easily achieved. You can define one action which will be dispatched in callFetch method. And in your newly defined action you can dispatch your mentioned two actions.

How I can loop through the similar objects in state and push them into object?

I've got several variables in my this.state object:
this.state = {
draw_number: '',
user_number_1: '',
user_number_2: '',
user_number_3: '',
user_number_4: '',
user_number_5: '',
user_number_6: '',
}
How I can loop through them and add them in the following object:
results {
numbers: [],
draws: x
}
This is my current solution:
this.state = {
draw_number: '',
user_number_1: '',
user_number_2: '',
user_number_3: '',
user_number_4: '',
user_number_5: '',
user_number_6: '',
}
}
submitHandler = () => {
let results = {};
for (let i=1; i<=6; i++) {
results = this.state['user_number_' + i];
}
console.log(results);
}
Right now I cannot console.log my 'results' object
You could extract the draw_number property from the state and use that as draws and then use Object.keys on the rest of the properties in your state and use those values as the numbers array.
submitHandler = () => {
let { draw_number: draws, ...rest } = this.state;
let results = {
numbers: Object.keys(rest).map(key => rest[key])
draws,
};
console.log(results);
}
You can use the [spread operator][https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax].
This way you can copy all keys from object (new in ECMAScript 2018):
const myFriend = {name: 'George', age: 12}
const mySuperFriend = { ...myFriend, superpowers: true }
NOTE
you shouldn't mutate the state object directly in react.
Instead, create a new object and setState it

Assign return value of function to object property in React Native

export default class Leaderboard extends React.Component {
constructor(props) {
super(props);
this.numLeaders = 10;
this.topPlayers = populateLeaderboard(this.numLeaders);
this.state = {
tableHead: ['', 'Name', 'Age', 'School', 'Points'],
//Trying to assign leaders array to tableTitle
tableTitle: (function(this.numLeaders) {
let leaders = [];
for (let i = 0; i < numLeaders; i++) {
leader.push(i);
}
return leaders;
}())
};
}
So I'm trying to generate an array within a function and then assign it as a return value to an object property. I'm not sure if I'm messing up with Javascript or React, I don't have a ton of practice with Javascript objects.
If you want to do it in your way, here it is:
this.state = {
tableHead: ["", "Name", "Age", "School", "Points"],
tableTitle: (() => {
const leaders = [];
for (let i = 0; i < this.numLeaders; i++) {
leaders.push(i);
}
return leaders;
})(),
};
}
A working example.
const state = {
tableTitle: (() => {
const leaders = [];
for (let i = 0; i < 10; i++) {
leaders.push(i);
}
return leaders;
})(),
};
console.log(state.tableTitle);
I skipped the argument part here since you can already reach numleaders. Why do you need an argument?
Also, I used an arrow function above to avoid binding this. If you stick to your version don't forget to bind it:
this.state = {
tableHead: ["", "Name", "Age", "School", "Points"],
tableTitle: function () {
const leaders = [];
for (let i = 0; i < this.numLeaders; i++) {
leaders.push(i);
}
return leaders;
}.bind(this)(),
};
Or, if you really want to stick to your original-original version :) you can try this one:
this.state = {
tableTitle: (function (numLeaders) {
const leaders = [];
for (let i = 0; i < numLeaders; i++) {
leaders.push(i);
}
return leaders;
}(this.numLeaders)),
};
You are passing the argument then getting it back. No need to bind this here since you are not using this.numLeaders in your function.
Here is an alternative with some spread syntax and keys.
this.state = {
tableHead: ["", "Name", "Age", "School", "Points"],
tableTitle: [...Array(this.numLeaders).keys()],
};
A working example:
const state = {
tableTitle: [...Array(10).keys()],
};
console.log(state.tableTitle);
But, if this data is not dynamic maybe the state is not a suitable place for it.

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

Categories

Resources