Issue using Ternary operator in UseState - javascript

I'm trying to do the following
const[name,setName]=useState(recipe!==null?recipe.name:'')
The name appears to never be assigned with the ternary operator. Do they just not work within useState?
I've also tried reassigning the name like:
if(recipe!==null){
setName(recipe.name)
I receive an error in the console about too many re-renders.
Is there any other way of assigning name conditionally?
Edit
This is the structure of recipe
const[recipes, setRecipes]=useState([
{
id:1,
name:'Chicken Curry',
ingredients:"Some ingredients",
steps:"Some steps",
energy:'2899',
fat:'28.5',
carbohydrates:'41.3',
protein:'12',
sodium:'1226',
preparationTime:'15',
difficulty:'Easy'
}
How I'm calling the const
<RecipeModal recipe={activeRecipe}/>
and the recipe modal
const RecipeModal=({recipe}) =>{

It's difficult to understand what is going on there but I will try to help. I guess that the recipe can be undefined instead of null. You could try below:
const [name, setName] = useState(recipe ? recipe.name : '');
In example above, we are simply checking if the recipe has a truthy value so the default state value will be an empty string if recipe is: null, undefined, 0 or "".
Regarding reassigning name state. Are you doing that inside a useEffect hook? Please review all your useEffect hooks to see if you are not changing a value that is present in a dependency array.
Infinite re-renders can be solved by adding an if statement to see if the value we want to assign to did really change. It could be also related to a place where you reassign a recipe. I could help further with a bit more code.

Try to use like this:
const[name,setName]=useState(recipe!==null?recipe.name:null)
Or if name is string type, then
const[name,setName]=useState(recipe!==null?recipe.name: " ")

Related

When spreading the prevstate of a React useState hook I'm recieveing the error: must have a '[Symbol.iterator]()' method that returns an iterator.ts

I'm having the following problem when trying to spread the prevstate of a React useState Hook.
Here is the code that is showing the problem:
setSelectedMetrics((prevState) => [...prevState, metric]);
I'm receiving this error when I'm trying to spread the prevState:
Type 'IMetrics[] | undefined' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)
Here is where I set up the state:
const [selectedMetrics, setSelectedMetrics] = useState<ISelectedMetrics[] | undefined>([]);
The state selectedMetrics comes from the parent component as props to its child component, where I consume the state.
Here is the type that I've created to selectedMetrics:
export interface ISelectedMetrics {
metricPath: string;
displayName?: string;
}
If anyone had been through this issue before and could help, I would appreciate it.
I already tried to find a solution in the community for this specif issue when spreading the prevstate of a React useState hook array, but I didn't find any applicable solution.
I solve my problem based on David answer. In some part of my code I was using selectedMetrics state to populate a table with some checkboxes. I've implemented some global checkbox to check all checkboxes, but this global checkbox didn't have a metricPath, so I defined it as undefined an pass it to a function as undefined.
The solution was remove the undefined from the type definition and fix the logic of the global checkbox to pass a metricPath with empty string, so when spreading the prevstate it didn't compare it to undefined.
Yes, you cannot spread an object into an array
var x = {'a':'b', 'c':'d'};
var y = [...x];
console.log(y);
"Uncaught TypeError: x is not iterable"

React useState: pushing a sub-array into an array

Am using function based component and am having trouble in pushing a subarray into a useState array.
my code is shown below. There is an array called mode coming from the props which i need to append it as a sub array of more
const ViewCharts = (props) =>{
//other codes
let [more,setMore] = useState([])
useEffect(()=>{
console.log(props.mode,' mode array')
let temp = [...more,props.mode]
console.log(temp, ': this will append to more')
setMore(temp)
setTimeout(()=>{
console.log(more,'after setting')
},2000)
},[//some value])
}
when the props.mode has value ['top','bottom'] i expect more to have value of [['top','bottom']] and when next time if the props.mode is ['top'] i need more to have [['top','bottom'],['top']]. but this is what am getting when i run the above code.
["top"] mode array
["top"] : this will append to more"
[] : "after setting"
why the setMore is not adding array even when the temp is having the expected value.
If I remember correctly the useState variable will change value in the next render when you set it. You are trying to read the new more value in the same render you've changed it (as you are reading it in the same effect you've set the value in), which will be [] the first time as that's how you initialised it.
Try creating a second useEffect with a more dependency to see if it gives you the value you want:
// You can also just console.log() before the return, needing no `useEffect` to see if the value indeed changed.
React.useEffect(() => {
console.log('More: ', more);
}, [more]);
https://reactjs.org/docs/hooks-state.html#recap
Line 9: When the user clicks, we call setCount with a new value. React will then re-render the Example component, passing the new count value to it.
I would suggest reading the hooks API to better understand how they work.

ES2016 default parameter as empty array causes "no-empty-pattern" warning

I am in the process of building a React app which I have used Create React App as the build-environment. Within one of my (class-based) components I have the following line within the componentDidUpdate() method:
const toast = ([] = this.props.toast.toast);
If my understanding is correct, this is ES2016 syntax for setting default values if a variable is undefined. (Please let me know if this is not correct, although it's not the primary point of this question).
When my React app renders, I get the following warning in the console: Unexpected empty array pattern no-empty-pattern.
I understand that ESLint "moaning" about the fact it's an empty array. But as I want an empty array in that situation, why does this cause a warning?
Can I simply tell ESLint to ignore it (using // eslint-disable-line no-empty-pattern)?
That is not doing what you think it's doing at all. It's not setting anything to an empty array, nor is it a syntax for default variables. What it's doing is abusing array destructuring syntax without benefit. Try it yourself: if you execute this code, the value of toast will be undefined:
const toast = ([] = undefined);
There is no ES6 syntax for default variables, as far as I know, other than default function parameters, which is quite different from what you're using. If you want default variable values, just use the tried-and-true method of short-circuiting:
const toast = this.props.toast.toast || [];
To elaborate, proper array destructuring works something like this (assuming this.props.toast.toast is an array):
const [first, second, third] = this.props.toast.toast;
first === this.props.toast.toast[0]; // true
second === this.props.toast.toast[1]; // true
third === this.props.toast.toast[2]; // true

Why is this counted as mutating state?

handleClick(event) {
let value = event.target.value;
this.setState({ question: (this.state.question += value) });
I get a warning:
Do not mutate state directly. Use setState()
react/no-direct-mutation-state
if I try to load the page with this code.
How can I fix it so it doesn't give me this warning?
It says to use this.setState, but that's what I'm doing.
You're doing an unnecessary assignment addition to this.state.question - you only need addition here. Furthermore, when updating state based on a previous value, the docs state:
React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
The proper way to update state based on a previous value is to pass in an update function that works off the previous value, i.e.:
this.setState(prevState => ({ question: prevState.question + value }));
The mistake is here :
this.state.question += value
+= is the operator used to add right operand to the left operand. You are trying to add value to this.state.question.
The correct way to do it is :
this.setState(previousState => ({ question: previousState.question + value }));
This is considered mutating state because you are assigning a value to this.state.question in the expression (this.state.question += value). I have pasted a link to a Code Sandbox you can view to see how to correctly implement this behavior.
Code Sandbox

Shorthand computed properties

Can anyone please explain why these don't evaluate to the same thing?
Ember.ArrayController.extend({
maxProducts: 5,
hasMaxProducts: function () {
return this.get('model.length') === this.get('maxProducts');
}.property('model.length'),
shorthandHasMaxProducts: Ember.computed.equal('model.length', 'maxProducts')
});
I'm using the hasMaxProducts property in a handlebars template successfully, and if I try switching to the shorthandHasMaxProducts property, I don't get the same results, nor does it seem that this property ever updates. This should happen when I add another model to the array collection. I've also tried computing with:
Ember.computed.equal('model.[]', 'maxProducts')
Ember.computed.equal('model.[].length', 'maxProducts')
The second argument of Ember.computed.equal cannot be a property name, it has to be a plain javascript value, so a string, integer, boolean etc.
http://emberjs.com/api/#method_computed_equal

Categories