concat strings to Reference react fc prop by constructed name from inside the component - reactjs

I have a series of commonly named properties, and I'd like to have the un-common part of the name used in other places. I know that wording is a little convoluted, but perhaps an example will help. What I want is something like:
const MyComponent = ({lgProp, xlProp, mdProp, smProp, defaultProp}) => {
let current = defaultProp;
let myString = 'foo';
['sm', 'md', 'lg', 'xl'].forEach(size => {
const newValue = // somehow get the value of the property ${size}Prop
if (current !== newValue) {
myString += ` ${size}: ${newValue}`;
current = newValue;
}
});
}
The canonical answer to this type of question seems to be here, but all of the answers there either refer to dynamically referencing keys in objects, or dynamically referencing variables in pure JS in the Window or this scope. I can't seem to make any of them work for referencing property names.
There are also several sections on dynamically creating property names for components, but that's the wrong direction for me.
Things I've tried:
newValue = `${size}Prop`; // string
newValue = [`${size}Prop`]; // string
newValue = [${size} + 'Prop']; // string
newValue = this[${size} + 'Prop'] // TypeError
I mean, there are only so many props, so I could just write a bunch of if statements, but that seems so inelegant. Is there an attractive/elegant way to variably reference the prop names?

Related

Getting a value inside props using variable

Has anyone tried getting a particular value inside a prop using a variable?
Normally, getting a particular data in props goes like
const dataValue = props.table.data.rowData.account_number
However in this instance I need the last part of the props to be a variable, because
the account_number value is not fixed and the name varies.
So is there a way that I use a variable instead of adding a fixed name on the past part of the prop call?
Like so:
let theVariable = *somethingNew*;
const dataValue = props.table.data.rowData.theVariable
You can do this through property bracket access:
let theVariable = somethingNew;
const dataValue = props.table.data.rowData[theVariable]
This can also be used during object creation:
const dataValue = {
[theVariable]: {}
}
Yes. You can do like this:
let theVariable = *somethingNew*;
const dataValue = props.table.data.rowData[theVariable];

Should be an array, but typeof says it's an object, Chrome console displays it as an array

I have this problem which may sounds stupid but I don't really understand the whys.
I declare it as a variable: let [ randomQuoterState, setrandomQuoterState ] = useState([]); Then pass it into a component inside the return: <UserOutput set={setrandomQuoterState} current={randomQuoterState} number={1}/>
The following code is inside the component:
let toSet = [];
toSet[props.number] = quoteArray[Math.floor(Math.random() * quoteArray.length)];
let quote = props.current;
if (quote[props.number]){
delete quote[props.number];
console.log("deleted")
}else {
console.log("this does not exist");
}
console.log(typeof(toSet[props.number]));
console.log(toSet[props.number].lenght)
console.log(toSet[props.number]);
quote[props.number] = toSet[props.number][Math.floor(Math.random() * toSet[props.number].lenght)];
props.set(quote);
The Consol displays it as an array, but the typeof function says its an object, and it doesn't have a length property.
I would appreciate any help or explanation, I thought about it a lot, but I couldn't come up with anything.
Arrays are objects in Javascript. In fact, there is no array type.
To see if it is an array, you should try console.log((toSet[props.number]).constructor.name) and do your checks against toSet[props.number] instanceof Array.
Do not use (toSet[props.number]).constructor.name == 'Array' in your comparisons, because you could have something that has inherited from Array but whose constructor name is different.
In JavaScript both object and array are of type Object.
In case you want to determine exact type, you can use constructor property.
const data = {};
data.contructor.name === 'Object'; // Returns True
const data = [];
data.contructor.name === 'Object'; // Returns True
data.contructor.name === 'Object'; // Returns False
Above can used to determine String, Date etc as well.
Alternatively you can use libraries like lodash which has function for these things.
However that is overkill I guess.
Hope it helps.

Why is the state mutating if I am using spread operator?

I have this code that I am testing on jsfiddle
onVote = (dir, index) => {
console.log(this.state)
const products = [...this.state.products]
products[index].votes = dir ? products[index].votes + 1 : products[index].votes - 1
console.log(this.state.products[index].votes)
// this.setState({products})
};
https://jsfiddle.net/hkL3wug7/2/
However, even though I am not setting State, the console log shows that the state is changes every time I click on the plus and minus signs.
I did the same as in this article https://medium.com/#giltayar/immutably-setting-a-value-in-a-js-array-or-how-an-array-is-also-an-object-55337f4d6702
const newState = [...state] // clone the array
newState[action.index].done = true
return newState
as far as I understand
(it is not duplicate of the other question, I am not asking for an efficient way)
As #Carcigenicate mentioned, you have created a shallow copy of the array which means you have a new array pointing to the same objects in the original.
To avoid mutating the original object, you will need to also create a copy of the one you would like to mutate, e.g.:
// Shallow copy of the array
const products = [...this.state.products];
// Shallow copy of the object within the array
const updatedProduct = { ...products[index] };
// Update the copy of the object
updatedProduct.votes = dir ? updatedProduct.votes + 1 : updatedProduct.votes - 1;
// Replace the object with the updated copy
products[index] = updatedProduct;
As #Carcigenicate mentioned in the comment, using the spread operator creates a shallow copy of the array. This is creating a problem for you because the expanded version of the array contains Objects which are passed by reference. So even though your local variable products is a new copy of this.state.products, they both contain references to the same Objects.
To achieve what you are trying to do, you would have to clone the objects in this.state.products. One possible way to do this is using Object.assign and replace your const products = [...this.state.products] with:
const products = [
Object.assign({}, this.state.products.Orange),
Object.assign({}, this.state.products.Apples),
Object.assign({}, this.state.products.Bananas)
]

Angular 2 / Typescript - how to check an array of objects to see if a property has the same value?

This question does it in Javascript, but I would have thought in Typescript I could do some kind of map/filter operation to do the same thing.
I have an array of objects called Room. Each Room has a property called Width (which is actually a string, eg '4m', '5m', '6.5m').
I need to check the entire array to see if all the widths are the same.
Based on that question I have this, but I was wondering if TypeScript has something better:
let areWidthsTheSame = true;
this.qp.rooms.forEach(function(room, index, rooms) {
if (rooms[index] != rooms[index+1]) areWidthsTheSame = false;
});
Any ideas?
FYI the linked question has a comment that links to these performance tests, which are interesting in the context of this question:
This can be done in the following way:
const widthArr = rooms.map(r => r.width);
const isSameWidth = widthArr.length === 0 ? true :
widthArr.every(val => val === widthArr[0]);
We first convert the rooms array to an array of widths and then we check if all values in widths arrays are equal.

initialized without binding with angular

I need to initialized without binding.
I've tried the following. But I did not succeed
$scope.emptyRow = $scope.newsCategories[1];
$scope.newsCategories[1].Name = "yes";
$scope.emptyRow.Name = "test";
alert($scope.emptyRow.Name); // alert => test
alert($scope.newsCategories[1].Name);// alert => test
I need this :
$scope.emptyRow = $scope.newsCategories[1];
$scope.newsCategories[1].Name = "yes";
$scope.emptyRow.Name = "test";
alert($scope.emptyRow.Name); // alert => test
alert($scope.newsCategories[1].Name);// alert => yes
How to do this?
This has nothing to do with binding, but rather basic javascript.
The line: $scope.emptyRow = $scope.newsCategories[1];
is explicitly saying that you want $scope.emptyRow and $scope.newsCategories[1] to be pointing to the exact same object. Hence, when you change a child value of either (like Name), it will effect the other.
It looks like you want to be able to copy the object in question. For that you can use angular.copy(). An example use in your case would be:
$scope.emptyRow = angular.copy($scope.newsCategories[1]);
Read here for more info.

Resources