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
Related
I'm fairly new to ReactJS and wrote this function I want to use to update an object in my state. It seems unable to use the "name" param to update my object and I don't really get why. I tried to code it in template literals as well.
const handleAccountingChange = (newValue, name, id) => {
const newState = selected.map((obj) => {
if (obj.id === id) {
return { ...obj, name: newValue };
}
return obj;
});
setSelected(newState);
};
I get no error in the browser console, but it doesn't update my state either. Any idea would be appreciated. I spent 2 hours on google but didn't find anything.
When you call obj.property = 'aaa' you set property to aaa.
What you try to do is update the property contained by the variable name, what you code does is update the property name.
To update a property from a variable you need to use :
const property = 'name'
obj[property] = 'aaa'
equivalente to :
obj.name == 'aaa'
This code solves your probleme :
const handleAccountingChange = (newValue, name, id) => {
// For the exemple I declare selected here
const selected = [ {id: 1, test: 'aaa'}, {id: 2, test: 'bbb'} ];
const newState = selected.map((obj) => {
if (obj.id === id) {
let myObj = {...obj};
myObj[name] = newValue;
return myObj;
}
return obj;
});
return newState; // instead ou can use setSelected(newState)
};
console.log(handleAccountingChange('ccc', 'test', 1));
const handleAccountingChange = (newValue, name, id) => {
const newState = selected.map((obj) => {
if (obj.id === id) {
return { obj[name]= newValue};
}
return obj;
});
setSelected({...newState});
}
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.
I'm updating an input field with an onChange event in React.
const handleUpdateText = (id, name, text) => {
const newItems = items.map( item => {
if (item.id === id) {
return {...item, [menuLang][name]:text } // <-- error here at ][
}
return item;
} )
setItems(newItems);
}
name and text and name attribute and value of target input field.
menuLang is a state variable (string, eg "en").
The items are something like this:
{
id: 1,
type: "menuitem",
isVisible: true,
en: {
name: "Salad",
desc: "Fresh, seasonal ingredients",
},
price: "10",
},
Without dynamic destructuring it work fine:
const newItem = {...item}
newItem[menuLang][name] = text;
return newItem;
// instead of: return {...item, [menuLang][name]:text }
Any ideas what's the mistake?
use computed property name
let item={id:1,type:"menuitem",isVisible:!0,en:{name:"Salad",desc:"Fresh, seasonal ingredients"},price:"10"};
console.log(item)
let name = 'name'
let text = "Orange"
let menuLang = 'en'
item = {...item,[menuLang]:{...item[menuLang],[name]:text}}
console.log(item)
I don't think there is a mistake here, but I also didn't think what you want to do is possible via destructuring - I think you have to go down the route of your second example here.
const items = [{id:12,name: 'dj' }];
const handleUpdateText = (id = 12, name='ann', text='sample') => {
const newItems = items.map((item) => {
const obj = {...item};
if (item.id === id) {
return {...obj, [menuLang]: {[name]:[text]}};
}
return obj;
});
console.log('item', newItems);
};```
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 ?? {};
This is my schema:
detail: [{
quantity: Number,
product:{
name: String,
code: Number,
price: Number
},
subtotal: Number
]}
This is my validations method
const validations = values => {
const errors = {
product: {}
}
if(!values.detail ||
!values.detail.length){
errors.detail = {_error: 'at
least one item must be
required'}
}
else{
const detailArrayErrors = []
values.detail.forEach(
(item,itemIndex) =>{
const detailErrors = {}
if(!item || !item.quantity){
detailErrors.quantity
='Required'
detailArrayErrors[itemIndex]=
detailErrors
}
if(!item || !item.subtotal){
detailErrors.subtotal
= 'required'
detailArrayErrors[itemIndex]
= detailErrors
}
//How can I access product
// in validations method
})
if(detailArrayErrors.length)
errors.detail =
detailArrayErrors
}
return errors;
}
export default validations;
product is my nested json object inside detail. Detail is an array. I want to validate product. How can I access a nested json object inside an array for validate it?
I've tried using for... of, but it makes not results.
I was searching on web but I couldn't find nothing.
How can I do that?
Anyone who knows?
values.detail.forEach(d=> console.log(d.product));
To get array of invalid e.g.:
let invalidItems = values.detail.filter(d => !d.product || !d.quantity ||
!d.product.name);
To do something on each item in array:
this.values.detail.forEach(i =>
{
let detailErrors = {'quantity': null, product: null};
if (!i.quantity)
{
detailErrors.quantity= 'Required'
}
if (!i.product)
{
detailErrors.product = 'Required'
}
if (i.product && !i.product.price)
{
detailErrors.product = {'price' :'Required'}
}
});