how to deal with Computed and Destructuring assignment in Vue3? - javascript

const index = ref('child1')
const children = {
child1:{ name:'foo' },
child2:{ name:'bar' },
}
// case 1. I want to destructur and get name variable when index variable is changed to 'child2'. Because computed is not used here, it is not responsive, name variable still is 'foo'
const {name} = children[index.value]
// case 2. After using computed
const child = computed(() => children[index.value])
// Because I used Computed, I got the child object, but I can't deconstruct it
// so I need to use child.name in the template, and i dont want that.
// My puzzle is how to use the name field directly, as in case 1, and responsive as in case 2
// maybe Reactive with toRefs?
I got a playground to explain my confusion
I expect to use the name field directly, as in case 1, and responsive as in case 2

a) deconstruct with toRef or toRefs:
const child = computed(() => children[index.value])
const { name } = toRefs(child)
const name1 = toRef(child, 'name')
b) get name directly
const childName = computed(() => children[index.value].name)
c) use Reactivity Transform (experimental)
const child = computed(() => children[index.value])
const { name } = $( child ) // name is string

You could define the computed to be the name directly:
const name = computed(() => children[index.value].name);

Related

Get JSON value by using variables on the 2nd level of depth

I have a .json file like this:
{
"width": 700,
"height": 1382,
"dataID": {
"id1": "54321",
"id2": "12345"
}
}
I need to get value of id1 or id2 keys dynamically (using a variable). I use Cypress function cy.read() and by using definite strings it works good:
cy.readFile(pathToConfigFile).then(($file) => {
const id1value = $file.dataID.id1;
});
But how to wrap this expression into variable containing id1?
There is a similar question : Dynamically access object property using variable
However the solution proposed there refers only to the first level of depth. With square brackets I can get the following values:
cy.readFile(pathToConfigFile).then(($file) => {
const customVariable = "dataID";
const id1value = $file[customVariable];
});
But in case of it returns id1value = undefined:
cy.readFile(pathToConfigFile).then(($file) => {
const customVariable = "dataID";
const id1 = "id1";
const id1value = $file[customVariable][id1];
});
You will need to check the value of the variable after the first check so you know whether you can read the second-level value.
cy.readFile(pathToConfigFile).then(($file) => {
const customVariable = "dataID";
const id1 = "id1";
const idValues = $file[customVariable];
return idValues ? idValues[id1] : undefined;
});
Instead of undefined you can return some default value if you prefer.
There are also packages which can be used to do this automatically for you, such as lodash's _.get() method.

Name of this switch operator syntax

I am constantly finding this sort of switch statement in a codebase and not being able to find documentation about it anywhere. Does anyone know the name of this syntax?
import React from 'react'
enum Options {
FirstOption = 'first',
SecondOption = 'second'
}
export default function DisplayIcon({selectedOption: string}) {
const clickFirst = () => {
// do something
}
const clickSecond = () => {
// do something
}
return (
<Wrapper>
{
{
[Options.FirstOption]: (
<ClickableIcon onClick={ clickFirst }>
<Icon type={ IconType.Frist } />
</ClickableIcon>
),
[Options.SecondOption]: (
<ClickableIcon onClick={ clickSecond }>
<Icon type={ IconType.Second } />
</ClickableIcon>
),
}[selectedOption]
}
</Wrapper>
)
}
It's not a switch statement at all, though you're right it's being used to select a value. It's an object literal with computed property names. So it's building an object, then picking out the property matching selectedOption from that object, all in the same expression.
Here's a simpler example of the object literal part with computed property names:
const name1 = "a";
const name2 = "b";
const obj = {
[name1]: "value for a",
[name2]: "value for b",
};
console.log(obj);
And here's an example of what that code is doing with building the object and then immediately grabbing one of its properties:
const name1 = "a";
const name2 = "b";
const pickOne = Math.random() < 0.5 ? name1 : name2;
const pickedValue = {
[name1]: "value for a",
[name2]: "value for b",
}[pickOne];
console.log(`Picked "${pickOne}": "${pickedValue}"`);
FWIW, I wouldn't do it that way. I'd either define the object once and reuse it, or use a switch or if/else if or similar in the code prior to the return.
This isn't specific to JSX, and isn't really a particular piece of syntax, but a combination of multiple. Let's simplify it a bit:
let result = {
[Options.FirstOption]: 'hello',
[Options.SecondOption]: 'goodbye',
}[selectedOption];
This will select either 'hello' or 'goodbye'. It does so by first creating an object, and then looking up a property on it. We could add an intermediate variable like this:
let options = {
[Options.FirstOption]: 'hello',
[Options.SecondOption]: 'goodbye',
};
let result=options[selectedOption];
The [...]: syntax is just to allow the keys themselves to be defined based on some other variable, rather than a literal string. We could instead add properties one at a time like this:
let options = {};
options[Options.FirstOption] = 'hello';
options[Options.SecondOption] = 'goodbye';
let result=options[selectedOption];
The result, as you already worked out, is equivalent to this:
let result;
if ( selectedOption === Options.FirstOption ) {
result = 'hello';
}
elseif ( selectedOption === Options.SecondOption ) {
result = 'goodbye';
}

Best way to reference an object property

Let say I have an object with
let product =
{ id:1,
model:2
}
I can reference the id by
const productId = product.id
Or I can also do
const newProductCreated = Object.assign({}, product)
then reference by newProductCreated.id
Which would be the best way for me to reference the id?
If you are working with the Redux/'Flux' methedology, the second method makes sense, it is not how you should be using it.
Assuming you are trying to create a shallow copy of the object, you can simply do this:
const productCopy = { ...product };
// or const productCopy = Object.assign({}, product) if you can't support ES6
From there, you can make respective changes to the properties within productCopy without affecting the original product.
productCopy.model = 3;
// console.log(productCopy) prints out the modified object
// console.log(product) prints out the original object
This will be conform to the immutable update patterns.

How do these 2 notations differ in meaning in React.js?

Came across these 2 notations recently. While both appear to be doing similar things, one of them uses an assignment operator while another one appears to be an object. Are they doing anything different?
const { value = "" } = this.props;
and
let { value: newValue } = newProps;
Both of these are destructing an object. When you use = you are setting a default value if the value is undefined/null. With : you are aliasing the variable. You can even combine them:
const { value : value2 = 'Hello' } = this.props;
console.log(this.props.value); // World
console.log(value2); // World (since value2 IS this.props.value aliased)
// ...or if this.props.value isn't defined
console.log(value2); // Hello
It has nothing to do with React library actually. They are ES6 destructuring assignments.
The first example will create a constant variable called value and will assign whatever is this.props.value (Object, Array, Number). If this.props.value is undefined though it will use default value = "" - empty string.
const { value = "" } = this.props;
In a second example, newValue variable will be created and it will equal to newProps.value (even if it is undefined).
let { value: newValue } = newProps;

How can I replace an item in an array with an object?

album.songs = [1234545, 43524];
const replaced = album.songs.map( e => { e = Object.assign({}, { _id : 123 }) } );
Output: undefined
My problem is that I would like to replace my items in 'songs' array with a specific object. It works with strings or numbers but not with objects.
Some notes:
With map, you return the object you want the new array to contain. Assigning to the parameter e just changes the value of the parameter, which isn't retained anywhere.
There's no need for Object.assign there, just create the object directly, so:
const replaced = album.songs.map(e => { return { _id : e }; } );
or the concise form:
const replaced = album.songs.map(e => ({ _id : e }) );
Note that since we want to return an object created with an object initializer, and the { in the initializer would start a function body, we wrap the value we want to return in ().
We can even take advantage of shorthand property notation if we change the name of the parameter to _id:
const replaced = album.songs.map(_id => ({ _id }) );
Live Example:
const album = {songs: [1234545, 43524]};
const replaced = album.songs.map(_id => ({ _id }) );
console.log(replaced);
You don't assign to the function parameter, since it only exists for that function, and it's not like you're dereferencing a pointer.
Just return the object. An arrow function automatically returns its expression if you don't use curly braces to denote the body.
var songs = [1234545, 43524];
const replaced = songs.map(e => ({_id: e}));
console.log(replaced);
Map function expects you to return a value for each iteration:
console.log([1, 2].map(n => n * 2))
In your case, it should be:
album.songs.map( e => ({ _id : e }))

Categories

Resources