destructing nested object in react prop got error - javascript

const {
user: { name }
} = props;
With the above code, I got
name of undefined when the user object is undefined
I like destructing but should it be used this way? The issue is there's no fallback to crash my react app. I rather do destruct and use ? as a fallback:
const {
user
} = props;
return <div>user?.name</div>

Try this instead:
const {
user: { name = '' } = {name: ''}
} = props;
<div>{name}</div>

In case that the property you are destructuring is not defined,
You can assign "Default values" like this:
const props = {diffUser: {name: "Peter"}};
const { user: {name} = {name: "default-value"} } = props;
console.log(name);
The simpler example,
var { message: msg = "Something went wrong" } = {};
console.log(msg);
A variable can be assigned a default, in the case that the value unpacked from the object is undefined.

You can just add a quick default value an check for undefined or null string after:
const { user: { name } = {} } = props;
This way it will not throw an error if 'user' is undefined, name will just be undefined also.

Related

How to destructure a nested object only when it has a value?

let notStudent, name, isRegistered
if (studentDetail && studentDetail.fields) {
({ notStudent, name, isRegistered } = studentDetail.fields)
}
Is there a way to write this logic without an if statement or in a succinct way?
You can destructure in this way. The tricky thing is when there is no fields property on studentDetail then javascript can throw an error, to tackle that case, you can set default empty object using || operator.
let studentDetail = {
fields: {
notStudent: '1',
name: '2',
isRegistered: true
}
}
let {
notStudent,
name,
isRegistered
} = (studentDetail && studentDetail.fields) || {};
console.log(notStudent);
console.log(name);
console.log(isRegistered);
You can destructure an empty default object in case your studentDetail.fields doesn't exist:
const { notStudent, name, isRegistered } = studentDetail?.fields ?? {};

Destructuring without "Uncaught ReferenceError: props is not defined"

I'm trying to find something about destructuring :
If I do something like this :
const { id, category: { categoryId } } = {};
It throws an error
VM136:1 Uncaught TypeError: Cannot destructure property "categoryId" of "undefined" or "null".
because we are trying to access props categoryId of category, but category is undefined.
Is there any solution to do this only on one line destructuring ? I tried :
const { id, category: { categoryId = null } = {} } = {};
OR
const { id, category: { categoryId } = { categoryId = null } = {};
But it does not works.
I can easily do that with :
const { id, category } = {};
let categoryId = null;
if (category) ({ categoryId } = category);
thanks all !
You can hav an IIFE that returns the destructed properties and add a check for category in it :
const obj = {
id: 5,
category: null
};
const {
id,
category: { categoryId }
} = (({ id, category }) => ({ id, category: category || {} }))(obj);
console.log(id, categoryId);
you must have categoryId on right side (in your props)
const { id, category: { categoryId } } = {id: 0, category: {categoryId: 0}}
or
const props = {id: 0, category: {categoryId: 0}} // your props have to look like this
const { id, category: { categoryId } } = props;
Unfortunately there's no syntax to allow you to optionally destructure if something exists, you have to first check that the thing you want to destructure exists.
There's a proposal for optional chaining and some discussion around how that might affect destructuring, but that's not going to help you in the short-term.
In the meantime, you could look at lodash get which prevents the error you're seeing being thrown and also allows you to also provide default values for when something doesn't exist.
If category is undefined the you cannot get categoryId.
const { id, category: { categoryId } } = { category: { categoryId: 1 } };
console.log(categoryId)
Yes you can with the default value
var { id, category: { categoryId } = {categoryId: 'some'}} = {}
console.log(categoryId)
// When you set a default value for categoryId to it will always get that default value
// in case the destrucutured value is undefined
var { id, category: { categoryId = null } = {}} = {};
console.log(categoryId)
To understand this you can transpile this to ES5 using babel
"use strict";
var _ref = {},
id = _ref.id,
_ref$category = _ref.category;
_ref$category = _ref$category === void 0 ? { categoryId: 'some' } : _ref$category;
var categoryId = _ref$category.categoryId;
console.log(categoryId);
You can clearly understand from this simplified code how destructuring works under the hood
check for the value from the object at the right side, if the value is found, ignore default value if there's any
If the value is not found or it is undefined, check for the default value if there's any else keep it as it is,
In the context of this example, if you see the id and category aren't found on object, so the value of them is undefined, but here we have a default value for the category so it uses than value to get value of category, which will be { categoryId : 'some' }. now when you de-structure category further you're actually destructuring {categoryId: 'some'}, so final value of categoryId will be some
in this example
var { id, category: { categoryId = null } = {}} = {};
value of category will be undefined so when you further proceed to get value of categoryId it checks value of category since it is undefined it uses null as default value

Why i cannot assign values to destructured object variables?

I have form in my website with onSubmit eventListener, so when user submits the form getCurrencyData function is executed. inside getCurrencyData function im checking whether the user entered value or not, if yes then im making apicall and destructuring generalCurrencyInfo object. The problem is that i cannot assign values to destructured object variables.
class App extends Component {
constructor(props) {
super(props);
this.state = {
generalCurrencyInfo: {
fullName: undefined,
name: undefined,
imageUrl: undefined,
price: undefined,
error: false
}
}
}
getCurrencyData = async (e) => {
e.preventDefault();
const CURRENCYNAME = e.target.elements.currencyName.value.toUpperCase();
//Checks if currency name is not empty
if (CURRENCYNAME) {
const APICALL = await fetch(`url`);
const DATA = await APICALL.json();
let generalCurrencyInfo = {
fullName:undefined,
name: undefined,
imageUrl: undefined,
price: undefined,
error: false
}
//this destructuring doesn't work
let {fullName, name, imageUrl, price, error} =generalCurrencyInfo;
if (DATA.Message === "Success") {
fullName = DATA.Data[0].CoinInfo.FullName;
name = DATA.Data[0].CoinInfo.Name;
imageUrl = `url`;
price = "price";
error = false;
}
this.setState({
generalCurrencyInfo: generalCurrencyInfo
})
}
}
render() {
return (
);
}
}
You have created 5 new variables here:
let {fullName, name, imageUrl, price, error} =generalCurrencyInfo;
Then you have changed this variables, but not generalCurrencyInfo object:
if (DATA.Message === "Success") {
fullName = DATA.Data[0].CoinInfo.FullName;
name = DATA.Data[0].CoinInfo.Name;
imageUrl = `url`;
price = "price";
error = false;
}
Here you set generalCurrencyInfo, what was not changed:
this.setState({
generalCurrencyInfo: generalCurrencyInfo
})
This will be fine:
this.setState({
fullName,
name,
imageUrl,
price,
error,
})
You can just reassign the values to your generalCurrencyInfo object, so no need to destructure:
// reassign values
if (DATA.Message === "Success") {
generalCurrencyInfo.fullName = DATA.Data[0].CoinInfo.FullName;
generalCurrencyInfo.name = DATA.Data[0].CoinInfo.Name;
generalCurrencyInfo.imageUrl = `url`;
generalCurrencyInfo.price = "price";
generalCurrencyInfo.error = false;
}
// or using the spread operator
if (DATA.Message === "Success") {
generalCurrencyInfo = {
...generalCurrencyInfo,
fullName: DATA.Data[0].CoinInfo.FullName,
name: DATA.Data[0].CoinInfo.Name,
imageUrl: `url`,
price: "price",
error: false,
};
}
But if you landed on this page looking to find out how to re-assign a value to a destructured object, you might want to check out this question: Is it possible to destructure onto an existing object? (Javascript ES6)

Flow and Javascript . Cannot call function because property is missing in object type

Using flow type checker to type hint my javascript code
const functionName = (name: string, newvalue:string , units: {}) :{} => {
//Obj to be returned
const returnObj = {};
//index of a event.target.
const indexofChange: number = units.findIndex(matchElement, {
name: name
});
....
....
}
Flow is giving me an error
Cannot call units.findIndex because property findIndex is missing in object type [1].
Thanks #Tholle
const functionName = (name: string, newvalue:string , units: Array<Object>) :Array<Object> => {
//Array to be returned
const returnArray:Array<Object> = [];
//index of a event.target.
const indexofChange: number = units.findIndex(matchElement, {
name: name
});
....
....
}
fixes this

Reducer cannot read property 'photos' of undefined? What am I doing wrong?

Here is the initial state of my reducer, and I need to set it up in this way due to some post processing I need to do:
const initialState = {
showAll: {
photos: null
}
}
Basically, I have a page where you see all your photos, and you can tag certain ones as your pinned photos.
Here's part of my reducer logic:
if (state.showAll.photos) {
const showAllState = state.showAll.photos;
showAllState.map(m => {
if (action.payload.id === m.id) {
m.pinned = true;
}
});
showAllAfterPin = showAllState;
} else {
showAllAfterPin = state.showAll.photos;
}
However, I get an error saying cannot read property 'photos' of undefined and I'm not sure what I am doing wrong.
Might be easier to just set your photos in initialState to empty array [] instead of null.
Another thing, your reducer should not mutate your state object.
Doing const showAllState = state.showAll.photos doesn't make it a new object.
Last thing, showAllState.map(...) needs to return an item inside the function body. It will create a new array.
Here's something you can do...
const { photos = [] } = state.showAll;
const updatedPhotos = photos.map(photo => {
if (action.payload.id === photo.id) {
return Object.assign({}, photo, { pinned: true })
}
return photo;
});
// return entire state if this is inside your root reducer
return {
...state,
showAll {
...state.showAll,
photos: updatedPhotos
}
}

Categories

Resources