why this.setState going to "is not a function"? - javascript

Im trying build simple app to learn how to make api calls.
When I'm trying to setState in react with onClick function I'v created, every time I'v tried to invoke I get
not a function
I tried to bind this like this:
this.setState(() => ({
rowPos: null
}).bind(this))
but that did not worked also, I get the error:
(intermediate value).bind is not a function
there is constructor with state object:
constructor(props) {
super(props);
this.state = {
endpoint: 'https://jolapatola5.fakturownia.pl/invoices.json',
params: {
api_token: 'B5Lg3uPBCMcDNX5lsQOM/jolapatola5',
invoice: {
"kind": "vat",
"number": null,
"sell_date": "2019-07-14",
"place": 'Lublin',
"sell_date": "2019-07-14",
"issue_date": "2019-07-14",
"payment_to": "2019-07-21",
"buyer_name": "aaa",
"buyer_tax_no": "5252445767",
"buyer_street": "aaa",
"buyer_post_code": "",
"buyer_city": "",
"seller_name": 'aaa',
"seller_street": '',
"seller_post_code": '',
"seller_city": '',
"seller_bank_account": '',
"seller_tax_no": '',
positions: [{
"name": "Produkt A1",
"tax": 23,
"total_price_gross": 10.23,
"quantity": 1
},
{
"name": "Produkt A1",
"tax": 23,
"total_price_gross": 10.23,
"quantity": 1
}
]
}
}
}
this.removeProductRow = this.removeProductRow.bind(this);
}
and method I'm trying to invoke onClick:
removeProductRow(id) {
let rowPos = this.state.params.invoice.positions[id];
this.setState(() => ({
rowPos: null
}).bind(this))
console.log(rowPos)
};
id is passed when I'm mapping components
The result I'm trying to perform is set the this.state.params.invoice.position alias rowPos to null, now its an object.
Thanks for any help
EDIT: there is the way I'm mapping components:
{
this.state.params.invoice.positions.map(function(item,index){
return
<ItemRow key={index} removeProductRow={() => this.removeProductRow(index)}/>
},this)
}

setState should be binded to React.Component, when you call this.setState.bind(this) you are actually binding it to removeProductRow, just remove the .bind(this)

There are two things I would do different.
First: Fixing the remove method.
removeProductRow(index){
let positionsUpdated = this.state.params.invoice.positions.filter((_, idx) => idx !== index);
// update just the positions of the state.
// try to create paramsUdpated yourself.
this.setState({params: paramsUdpated});
};
Second: In render I would not pass callback to props, just the name of the function and use prop itemIndex to get the index of the positions array in ItemRow component.
{this.state.params.invoice.positions.map(function(item,index){
return (<ItemRow key={index} itemIndex={index} removeProductRow={this.removeProductRow}/>)}
Working example of my idea: https://codesandbox.io/s/priceless-sun-tb76r

Related

VUE3 - VUEX v-model on an object

I am using Vue3's Composition API and would like to store some search parameters in my store.
My state:
const state = () => ({
selection: {
selected_cabins: "M",
flight_type: "round",
adults: 1,
children: 0,
infants: 0,
pets: 0,
fly_from: "",
fly_to: "",
start_date: "",
return_date: "",
},
});
I'm trying to use it like so:
<q-select
borderless
:options="flightType"
v-model="selection.flight_type"
option-value="value"
emit-value
map-options
/>
Computed Property:
const selection = computed({
get() {
return store.state.flights.selection;
},
set(val) {
store.commit("flights/SET_SELECTION", val);
},
});
But I am still getting the error that I cannot mutate state outside of a mutation.
If I break the object (selections) down to its properties I can get it to work, but thats really verbose. Is there anyway to do the above with an object as I have it?
In v-model you're accessing the nested state value which mutates that state, the right syntax should be like :
v-model="flight_type"
and in the setter spread the state with modified property :
const flight_type = computed({
get() {
return store.state.flights.selection.flight_type;
},
set(val) {
store.commit("flights/SET_SELECTION",
{...store.state.flights.selection,flight_type:val);
},
});

Javascript destructuring data in react

I am using react-native and I am trying to pass data to child component, and after that I want to use map method for displaying user data with key value.
So i get this data after making array from object, how should i destruct it to get username etc..
PARENT COMPONENT:
render() {
let userMap = Object.entries(this.state.users).map(key => key);
return (
<ViewPager
users={userMap}
usersRetrieved={this.state.usersRetrieved}
addNewMatch={this.addNewMatch}
navigation={this.props.navigation}
/>
);
CHILD COMPONENT:
<Text>{JSON.stringify(props.users)}</Text>
How should i get username or profile_picture data?
I tried to do props.users[0].username but no luck
DATA EXAMPLE WITH 3 USERS:
{
"lwcIQTcpAae4e38hrD2K5Ar76W93": {
"email": "emilissssss#temp.lt",
"fbid": "3008*******71455",
"gender": "male",
"profile_picture": "...",
"username": "Emilis"
},
"tempuser": {
"email": "temp#temp.lt",
"fbid": 315151515,
"gender": "female",
"matches": {
"lwcIQTcpAae4e38hrD2K5Ar76W93": [Object]
},
"profile_picture": "...",
"username": "Egle"
},
"thirdUserID":{
"email": "temp#temp.lt"
"username": "thirdUserUsername"
...
}
}
Have you tried doing props.users[0][1].username instead? Since it seems to be the second value of an array inside an array
You can update userMap variable in parent component like
let userMap = Object.entries(this.state.users).map(([key, value]) => value);
This returns an array of user objects like:
[{
"email": "emilissssss#temp.lt",
"fbid": "3008*******71455",
"gender": "male",
"profile_picture": "...",
"username": "Emilis"
},
{
"email": "temp#temp.lt",
"fbid": 315151515,
"gender": "female",
"matches": {
"lwcIQTcpAae4e38hrD2K5Ar76W93": [Object]
},
"profile_picture": "...",
"username": "Egle"
},
{
"email": "temp#temp.lt"
"username": "thirdUserUsername"
...
}
]
Then in child component you can simply .map() over all users like:
{props.users.map(user => (
<Text>{user.username}</Text>
))}
Edit:
As, you need the userid also, then update userMap variable in parent component like:
let userMap = Object.entries(this.state.users);
Then in the child component, update map like:
{props.users.map(([key, user]) => (
<Text>{key}</Text>
<Text>{user.username}</Text>
))}
Or,
{props.users.map(([key, user]) => (
<Text>{key + ', ' + user.username}</Text>
))}
You can do the following thing:
{props.users.map(user => (
<Text>{user[0].username}</Text>
))}
What are you trying to do with Object.entries(this.state.users).map(key => key); ? Object.entries already returns an array so there's no need to map it afterwards like that I reckon.
Anyway, to destructure an object in js:
const obj = {
a: "value",
b: "other value",
}
const {a,b} = obj
// a "value", b "other value"
Note that the variable and the key should be named the same.
And now you have a and b as constants available in your code.
In your child component you could have smth like this:
render() {
let users = props.users
return users.map(user => {
const {username, email} = user; // destructure whatever you want
return <Text>{email} {username}</Text> // display it the wy you want
});
}
Array appears to be tied up several times.
The value you want is in the second index of the second array.
{props.users.map(user => (
<Text>{user[1].username}</Text>
))}

I stuck the change methods.properly fetch JSON to normal method

enter image description here
export default class App extends Component {
state = {
currentCategory: "",
products: [],
cart: []
};
componentDidMount() {
this.getProducts();
}
changeCategory = category => {
this.setState({
currentCategory: category.categoryName
});
this.getProducts(category.id);
};
getProducts = categoryId => {
let url = "http://localhost:3000/products";
if (categoryId) {
url += "?categoryId=" + categoryId;
}
fetch(url)
.then(response => response.json())
.then(data => this.setState({
products: data
}));
};
//////////////////////////////////////////////////
export default class App extends Component {
state = {
currentCategory: "",
products: [],
cart: []
};
componentDidMount() {
this.getProducts();
}
changeCategory = category => {
this.setState({
currentCategory: category.categoryName
});
this.getProducts(category.id);
};
getProducts = (categoryId) => {
var item = db.products;
console.log(item.categoryId);
this.setState({
products: item
});
}
}
/////Json format like shown below//////
{
"products": [{
"id": 1,
"categoryId": 1,
"productName": "Chai",
"quantityPerUnit": "48 - 6 oz jars",
"unitPrice": 23,
"unitsInStock": 53
}],
"categories": [{
"id": "1",
"categoryName": "Beverages",
"seoUrl": "beverages"
}]
}
in this first part work correctly when i fetch data from api. But when i wanna fetch json data from local its fine i can but not work properly as first method. At the first method filter products by categoryId but i cant handle this filter.
console.log(item.categoryId); with this code i try to look can i get proper id's item on console but İ can see only undefined and if i use this.setState({products:item.categoryId}); then i take an error of about map function.
in this picture when i click one of category at the left side its filter the right side of products. İ can use this only first code i couldnt change properly.

'Cannot read property 'DV' of undefined' when reading information from state of component in React

Undefined error when trying to read information from a JSON object in 'this.state'.
Component Class:
class App extends Component {
state = {}
// Code is invoked after the component is mounted/inserted into the DOM tree.
componentDidMount() {
const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY'
fetch(url)
.then(response => {return response.json()})
.then(data => {
this.setState(data)
})
}
render() {
console.log(this.state.SiteRep.DV)
return <p>TEXT</p>
}
}
export default App
Json Object:
{
"SiteRep": {
"Wx": {
"Param": [
{
"name": "FDm",
"units": "C",
"$": "Feels Like Day Maximum Temperature"
},
{
"name": "FNm",
"units": "C",
"$": "Feels Like Night Minimum Temperature"
},
...
]
},
"DV": {
"dataDate": "2019-10-09T13:00:00Z",
"type": "Forecast",
"Location": {
"i": "354287",
"lat": "52.0951",
"lon": "1.3143",
"name": "WOODBRIDGE",
"Period": [
{
"type": "Day",
"value": "2019-10-09Z",
"Rep": [
{
"D": "W",
"Gn": "22",
"Hn": "66",
"PPd": "8",
...
},
{
"D": "WSW",
"Gm": "22",
"Hm": "87",
"PPn": "1"
}
]
},
{
"type": "Day",
"value": "2019-10-10Z",
"Rep": [
{
"D": "WSW",
"Gn": "29",
"Hn": "61",
"PPd": "5",
},
{
"D": "SW",
"Gm": "34",
"Hm": "87",
"PPn": "19",
}
]
}
...
]
}
}
}
}
I am going to map the "Period" list to map some elements, however when trying to access said part of the Object in 'this.state', I am greeted with the error 'Cannot read property 'DV' of undefined'
The object is found within state, all the Json data is correct and I can access it in Console when I am not beyond the '.SiteRep' object. Feel like I am doing something very wrong :D
The issue here is, although you get your Json in componentDidMount, render() happens before fetch is completed. Just by checking whether data is available before accessing it would solve your issue.
class App extends Component {
state = {}
// Code is invoked after the component is mounted/inserted into the DOM tree.
componentDidMount() {
const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY'
fetch(url)
.then(response => {return response.json()})
.then(data => {
this.setState(data)
})
}
render() {
if(this.state.SiteRep){
console.log(this.state.SiteRep.DV);
}
return <p>TEXT</p>
}
}
export default App
This is a lifecycle issue. ComponentDidMount triggers after the component has loaded, which means this.state.SiteRep.DV does not exist yet. You'll need to add a check to see if SitRep exists on state so it doesn't error out.
So...
if(this.state.hasOwnProperty('SiteRep') console.log(this.state.SiteRep.DV)
Here's the expected behavior of the component:
First render happens
=> `ComponentDidMount` is fired
=> Request is made and response is set to state
=> setState triggers another render where SiteRep does exist on state
Then for your JSX:
render() {
if(this.state.SiteRep && this.state.SiteRep.DV) {
return <p>interpolate a value from {this.state.SiteRep.DV.someStringProp} </p>
}
return null
}
Please consider going through React's Component lifecycle one more time here.
This is what's happening in your code:
Your component state is initialized to empty object.
Component's render() method is called (where you don't have the data you need).
Lifecycle method componentDidMount() is called after initial render(), where you make an API call and update the state with response data.
One way to solve this -
You can consider having a flag isFetching in your state which is set to true initially.
state = { isFetching: true };
Update your render() method to display a fallback UI until your API call is successful i.e. isFetching is false;
...
render() {
const { isFetching } = this.state;
if (isFetching) {
return <span> Fetching data </span>;
}
console.log(this.state.SiteRep.DV)
return <p>TEXT</p>
}
...
Add changes to update your isFetching flag when API call is being made:
...
componentDidMount() {
// You're going to call the API now, set isFetching to true
this.setState({ isFetching: true });
const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY'
fetch(url)
.then(response => {return response.json()})
.then(data => {
// API call done, set data and make isFetching false.
this.setState({ data, isFetching: false });
})
}
...
Another approach would be to add the initial state such as:
state = {
SiteRep: {
DV: {}
}
}
With this approach, initially you would see no data but once API response is updated in your component state, component will re-render.
Personally I'd take the first approach as you can have finer control over your render()

javascript map.set not working when trying to add new property to redux state

I have a list of maps like the following in my redux state
[
{
"id": "id1",
"code": "code0"
},
{
"id": "id2",
"code": "code1"
}
]
I am unable to add a new property to the above list of maps. Below is the code which I use to add a new property to the map
case SET_NEW_PROPERTY: {
const a = currentState.get('reduxstate')
a.forEach((mapObj, index) => {
mapObj.set('newproperty', 'value')
}
return currentState.set('reduxstate', a)
}
I am not sure why the set is not working. Any help is appreciated. Thanks in advance.
You should use plain object in redux store, In this case, add new property to Map doesn't changed state, it's same reference to Map.
When connect to Pure React Component, cause props didn't changed, UI will not update.
And mention, when try to add property to plain object in reducer, you should return new object, or you can use combineReducers, it will automatic return new object when any property value changed.
UPDATED: You can use the spread operator and map. something like this
state = [
{
"id": "id1",
"code": "code0"
},
{
"id": "id2",
"code": "code1"
}
];
then simply add new object like this
[
...state,
{
"id": "id3",
"code": "code3"
}
]
UPDATE: However, if you want to add a new property to the map then you can do this.
const newState = state.map( item => ({ ...item, "newProperty": "newvalue", }));

Categories