this.state return empty array when render - react-native

I wanted to display the array series and when I tried to console the array this.state.series in the function it does has the result and the value inside but when I render this.state.series just keep giving empty array. I wonder is it because of the componentDidMount()?
constructor(props){
super(props);
this.state={series:[]}
}
GetTransaction=()=> {
var APIURL="http://10.0.2.2:80/api/getTransaction.php";
var headers={
'Accept':'application/json',
'Content-Type':'application.json'
}
fetch(APIURL,
{
method:'POST',
headers: headers,
})
.then((response)=>response.json())
.then((response)=>
{
this.setState({results:response});
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
console.log(this.state.series)
})
.catch((error)=>
{
alert("Error"+error);
}
)
}
componentDidMount(){ // runs after the component output has been rendered to the DOM
this.GetTransaction();
}
render(){
console.log(this.state.series)
output
Array []
Array []
Array []
Array []
Array []
Array []
Array []
Array [
"1",
"2",
"1",
"1",
]

There are basically 2 errors in GetTransaction state assignment:
you can't read a state just assigned because this.setState is async. If you want to get the very last value of state you should use this.setState's callback:
this.setState({results:response}, () => {
console.log(this.state.result); //<-- here you have the very last value of result
});
state must be always setted with this.setState: this.state.series.push(a.count) is not good.
So you have to rewrite your code in this way:
...
this.setState({results:response}, () => {
let seriesAppo = [];
this.state.results[0].map((a) => {
seriesAppo.push(a.count);
});
this.setState({series: seriesAppo}, () => {
console.log(this.state.series);
})
});
...

That‘s weird
this.state.results[0].map((a) => {
this.state.series.push(a.count)
});
Don‘t manipulate state that way, only with setState.
const series = response[0];
this.setState({series: series});
Even if you wanna add elements to an array you have to recreate the array. You can achieve this as follows:
const series = response[0];
this.setState({series: […this.state.series, …series]});

Related

How to store array of object in react nativr async storage

I'm trying to set an array of objects in React Native AsyncStorage.
However, just the 1st item will store in it.
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify({
data: totalSet,
name: props.index,
date: today.toISOString().substring(0, 10),
})
the first item (data) is an array
Update
In my workout tracker app,
I try to create nested object. in the child component, I have following data:
weight: number
reps: number
result: also number (combination of weight and reps)
setIndex :number, which indicate the index of each sets
I have sent above data to parent component like this:
Child component
onPress={() =>
childToParent({
setDetails: [
{
setIndex: setIndex,
result: result,
weight: weight,
reps: reps,
},
],
}) + buttonStatus()
in the parent, I have given data, and trying to add into exsiting array and also adding 2 more item, date and index of each workout
parent component
const [totalSet, settotalSet] = useState([{ today }, { index }]);
useEffect(() => {
if (data != 0) {
settotalSet((current) => [...current, data]);
}
}, [data]);
then I store it into asyncstorage
const storeData = async () => {
try {
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify(totalSet)
).then((res) => console.log(res));
} catch (e) {
// saving error
}
};
and get it into another component like this
getMyObject = async () => {
try {
await AsyncStorage.getItem('1512').then((res) => {
setData(JSON.parse(res));
});
} catch (e) {
// read error
}
};
Finally as a result, I have below array:
Array [
Object {
"today": "2022-09-04",
},
Object {
"index": "1512",
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 13.200000000000001,
"setIndex": 0,
"weight": "12",
},
],
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 26.400000000000002,
"setIndex": 1,
"weight": "24",
},
],
},
]
everything is fine, except I need a nested object and this is an array.
How to create such an nested object at the first place?

Reordering Array for Todos in MST Mobx State Tree

I would like to reorder arrays when using mobx state tree.
Say I have this example taken from the example page.
How do I get to reorder my ToDos in the TodoStore.
As a simplified example, say my todos are ['todo1, todo2'], how do I change them so that the new array is ['todo2, todo1']?
const Todo = types
.model({
text: types.string,
completed: false,
id: types.identifierNumber
})
.actions((self) => ({
remove() {
getRoot(self).removeTodo(self)
},
edit(text) {
if (!text.length) self.remove()
else self.text = text
},
toggle() {
self.completed = !self.completed
}
}))
const TodoStore = types
.model({
todos: types.array(Todo),
filter: types.optional(filterType, SHOW_ALL)
})
.views((self) => ({
get completedCount() {
return self.todos.filter((todo) => todo.completed).length
},
}))
.actions((self) => ({
addTodo(text) {
const id = self.todos.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1
self.todos.unshift({ id, text })
},
removeTodo(todo) {
destroy(todo)
},
}))
export default TodoStore
Thanks a lot!
If you want move the second todo to the first index in the array you could create a new action and splice the second todo out and then unshift it back in:
swapFirstTwoTodos() {
const secondTodo = self.todos.splice(1, 1)[0];
self.todos.unshift(secondTodo);
}

Vuex passing different arrays

Making a filter:
Mutations
export default {
state: {
filteredBrands: []
},
mutations: {
showFilteredList(state, payload) {
state.filteredBrands.push(payload);
}
}
};
Methods
loadProducts(item) {
axios.get('/api', {
params: {
per_page: 20,
filter_machinery_brands: [ item ]
}
})
.then((response) => {
this.$store.commit(
'showFilteredList',
response.data
);
});
},
item this is an input with a checkbox, when clicked, a request is made to the server for this category
For some reason, the push does not work, why?
And I would like there to be a check, if the array is the same, then delete, otherwise add. Is it possible?
If you can se an array comes in as payload. Then you are trying to push an array into an array. Which cant be done in either js or ts.
You can try set the value:
state.filteredBrands = payload;
otherwise you would have to do something like this:
state.filteredBrands.push(payload[0]);
If you wanna control for existing items in array, and assuming your are not always setting value, but pushing new values into your array. You can do something like this:
if (state.filteredBrands.indexOf(payload[0]) === -1) {
// Not in array
state.filteredBrands.push(payload[0])
} else {
// is allready in array
state.filteredBrands.forEach((item, index) => {
if (item === payload[0]) {
state.filteredBrands.splice(index, 1)
}
})
}
EDIT:
My assumption was right.
Your payload is an array
Your state is an array
-------> You are trying to push payload(array) into state(array) - which cant be done i js - This solution would after my suggestion be more clean:
payload.forEach((value, index) => { // Looping payload
if (state.filteredBrands.indexOf(value) === -1) {
state.filteredBrands.push(value) // push if value not allready in array
} else {
state.filteredBrands.splice(index, 1) // if value is in array -> remove
}
})
Yes, you can push an array into an array.
I guess the problem here is your vuex config.
Vuex state is a function, so it needs to be:
state () {
return {
filteredBrands: []
}
}
And if you are using Nuxt:
export const state = () => ({
filteredBrands: []
})

TypeError: Cannot read properties of undefined (reading 'products')

I am trying to get products, then check if the product pId is in an array, and filter if it is.
I get an error when i soft refresh of 'TypeError: Cannot read properties of undefined' (reading 'products'), almost like my 'this.products' isnt populated yet when computed is trying to get the data. Tried adding some if statements to check data is there but no luck.
<script>
export default {
data() {
return {
popular_products: [],
products: [],
}
},
computed: {
bestsellers() {
const keywords = this.popular_products
let array = []
for (var index = 0; index < keywords.length; index++) {
const keyword = this.products.data.products.product.filter(
(product) => product.pId == keywords[index].ProductNumber
)
array = array.concat(keyword)
}
return array
},
},
mounted() {
axios
.get(
'https://myurl/admin/api/collections/get/popularproducts?token=account-9306f9192049d3c442e565f2de5372'
)
.then((response) => (this.popular_products = response.data.entries))
axios
.get('https://myurl/products.json')
.then((response) => (this.products = response))
},
}
</script>
The problem is with this line:
let keyword = this.products.data.products.product.filter(product => product.pId == keywords[index].ProductNumber);
more specific with this read: data.products.
You see, computed property bestsellers is evaluated before your axios calls are finished.
Because of that, Vue can't find products in data because your this.products doesn't have data key.
The best solution would be to change this assignment:
- .then(response => (this.products = response)); // delete this line
+ .then(response => (this.products = response.data.products)); // add this line
Update After comment.
if (this.products.product) {
return this.products.product.filter(...)
} else {
return []
}

updating the state in componentWillMount

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 = [],
}
}
componentDidMount() {
console.log(this.state.inputValue)
this.props.navigation.setParams({ sendDataToServer:
this._sendDataToServer });
}
async componentWillMount(){
for(var key in dataList){
this.setState({
inputValue: {
...this.state.inputValue,
[dataList[key].inputFieldId]: dataList[key].data
}
})
}
}
code output = { 2: '120'}
thanks in advance
setState work asynchronously. Instead of this
this.setState({
inputValue: {
...this.state.inputValue,
[dataList[key].inputFieldId]: dataList[key].data
}
})
Try to change to this
this.setState((previousState) => ({
inputValue: {
...previousState.inputValue,
[dataList[key].inputFieldId]: dataList[key].data
}
}))