React useState: pushing a sub-array into an array - javascript

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.

Related

Issue using Ternary operator in UseState

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: " ")

Why can I only call this function once?

I am trying to build switches that create an array and have this so far:
const [playgroundFilters, setPlaygroundFilters] = useState([initialF]);
const updateItem = (whichvalue, newvalue) => {
let g = playgroundFilters[0];
g[whichvalue] = newvalue;
setPlaygroundFilters(g, ...playgroundFilters.slice());
console.log(playgroundFilters);
};
When I call up updateItem onPress it works once and every subsequent time I get an error "undefined is not an object evaluating g"
Is there an easy way to fix this?
setPlaygroundFilters expects an array so you would need to call it like that
setPlaygroundFilters([g, ...playgroundFilters.slice()]);
instead of
setPlaygroundFilters(g, ...playgroundFilters.slice());
I'm not sure you actually wants to use .slice() like that here, since it just returns the same (cloned) array.

React state is undefined , even though console.log shows it

I have researched other cases when the state was unidentified but I am still unsuccessfully trying to subtract data from UI actions that is in the format [{},{}...]. I have managed to add to the array , using this code, which in the same time also computes the total for the item (subTotal and products are props from a child component got through a callback function):
const updateTotalPriceAndUpdatePieChartData = (subTotal,product) => {
//from here
setPieChartData([...pieChartData,{product,subTotal}])
//until up, we handle what data we need for the pieChart
setTotal(total => total + (Number.isFinite(subTotal) ? subTotal : 0))
console.log("TOTAL WAS COMPUTED")
}
And this is the state that holds the array:
const [pieChartData,setPieChartData]=React.useState([])
Yet when I try to delte an object from the state array (when an item is also deleted), I try the following :
const substractSubTotalAndSubstractTotalForPieChart = (subTotal,product,pieChartData) => {
setTotal(total - subTotal)
const lastPieChartData=pieChartData.filter(item => item !={subTotal,product})
setPieChartData(lastPieChartData)
}
It says that pieChartData is unidentified. Could you please let me know what I can do?
In substractSubTotalAndSubstractTotalForPieChart method, there is a paramter pieChartData, but there is also a state with the same name. So what happens is inside the function substractSubTotalAndSubstractTotalForPieChart's scope, the parameter pieChartData is given preference rather than the state.
Hence in your method invocation, when you don't pass this parameter, the default value of an uninitialized parameter, i.e., undefined is used.

What's the drawback of `let count = useRef(0).current`

Example Code:
(Pretend we are inside component function)
let count = useRef(0).current
useEffect(()=>{
count++
console.log(count)
}, [count])
Question:
What will happen if I run this code
(I am afraid that the endless loop execution will blow up my m1 chip macbookair, so I didn't run ^_^).
Should I awalys some_ref_object.curent = some_value to change the value?
The code probably will not do what you expect.
useRef returns a mutable object, where the object is shared across renders. But if you extract a property from that object into a variable and then reassign that variable, the object won't change.
For the same reason, reassigning the number below doesn't change the object:
const obj = { foo: 3 };
let { foo } = obj;
foo = 10;
console.log(obj);
In your code, the ref object never gets mutated. It is always the following object:
{ current: 0 }
So
let count = useRef(0).current
results in count being initially assigned to 0 at the beginning of every render.
This might be useful if for some odd reason you wanted to keep track of a number inside a given render, not to persist for any other render - but in such a case, it'd make a lot more sense to remove the ref entirely and just do
let count = 0;
Your effect hook won't do anything useful either - since count is always 0 at the start of every render, the effect callback will never run (except on the first render).
Should I awalys some_ref_object.curent = some_value to change the value
You should use current, not curent. But yes - if you want the change to persist, assign to a property of the object, instead of reassigning a standalone variable. (Reassigning a standalone variable will almost never have any side-effects.)
But, if you have something in the view that the count is used in - for example, if you want to return it in the JSX somewhere - you probably want state instead of a ref (or a let count = 0;), so that setting state results in the component re-rendering and the view updating.
I just tried it on my colleague's computer, and fortunately it didn't blow up
Conclusion 1:
The useEffect won't effect, because ref can't be denpendency.
Conclusion 2:
Only let count = useRef(0).current is the right way.

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

Categories