Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have an object as a state with some properties. I want to update the state in a condition with a hook.
But it causes an infinite loop.
Can I update the state directly like this?
const [info, setInfo] = useState({name: '' })
if (info.name === '') {
info.name = 'empty'
}
Is this ok to do?
you should use useState as said in the following way:
const [info, setInfo] = useState({name: '' })
if (info.name === '') {
setInfo({...info, name = 'empty'});
}
this will set info with only the change of the name property
A hook is something that starts with use like useState. setState is not a hook - it's a setter/updater. It can be used inside of a conditional statement. If it's done properly there shouldn't be any infinite loops.
In React Functional Components, useState hook is used as an alternate to state in class components. The correct way to use the useState hook is
const [ variable, setVariable ] = React.useState( //default value );
The default value can be null, " string ", { object } , true / false, or 0, 1, 2 .......
And just like this.setState() in class components, you set the state with the
setVariable( newValue );
Never ever try to change the state variables like you change the normal variables. They are immutable for one render and hence cause re-render when called setState.
And for the infinite loop, please copy paste your component
Related
I am getting an object location from another page like this.
const location = useLocation();
I am trying to set a variable like this.
if (location.state !== null) {
console.log(location.state.name.companyName)
setcompanyOneAlready(location.state.name.companyName);
console.log(companyOneAlready);
}
But this results in a "Too many renders" error. I realize it's because of the way I am setting companyOneAlready but I don't know how to correct this. Any help is appreciated.
It seems you are running the code as an unintentional side effect and the condition is malformed.
Use the useEffect hook with correct dependencies to issue the side-effect to update state.
Example:
useEffect(() => {
if (location.state !== null) {
setcompanyOneAlready(location.state.name.companyName);
}
}, [location.state]);
To help save a rerender you can also check the current companyOneAlready value prior to enqueueing the state update.
useEffect(() => {
if (location.state?.name?.companyName !== companyOneAlready) {
setcompanyOneAlready(location.state.name.companyName);
}
}, [location.state, companyOneAlready]);
It seems like location.state is never null. I believe by default it is an empty object and {} !== null is always true. Also, I assume that setcompanyOneAlready changes the state in the component. That triggers rerender and your's condition will be true on every render. That's the reason why you get the mentioned error.
You should put this condition inside useEffect and useEffect should have a name or companyName in the dependency array to rerun the effect only when some of these values are changed.
im having problems with this line:
useEffect(() => {
if (AplicationsList) {
setDetail({ ...Detail, components: AplicationsList });
}
}, [AplicationsList]);
When AplicationsList its an empty array [] it gives me an error, like Detail is then undefined. But when its not empty works fine...
either if the array its empty or not I have to set the value on components attribute of Detail.
Any idea why this is happening?
This is the error I'm facing in the child component that depends on "Detail" passed as props:cannot read property map of undefined
And I get this react warning:
can't perform a react state update in an unmounted component
I've tried with this functional update but still is giving me the same errors:
setDetail(Detail => ({
...Detail,
components: AplicationsList,
}));
From you question, I understand Details is an object and AplicationsList is an array.
I think you have set the state of details this way or similar to this
const [Details, setDetails] = useState();. The problem with this is the initial value of Details is undefined and you are trying to destructure undefined. Instead set it as const [Details, setDetails] = useState({});
In useEffect you are checking if AplicationsList is empty, but if(AplicationsList) return true even for empty array. So check for the length instead, if(AplicationsList.length > 0)
Suggestion: It's good practice to have the state variable name to be of lowerCase and follow camleCase format to name variable. Instead of Details and ApplicationsList, its good you rename to details and applicationsList.
React docs state: don’t call Hooks inside loops, conditions, or nested functions.
Does calling a hook means just calling useState e.g. const [state, useState] = useState(0)?
What about calling setter in conditionals ?
Is this code breaking rules of hooks ?
const [oneHook, setOneHook] = useState(0)
const [anotherHook, setAnotherHook] = useState(false)
if (something) {
setOneHook(1)
setAnotherHook(true)
} else {
setOneHook(0);
setAnotherHook(false)
}
Thanks !
No, that code example does not break the rules of hooks. Every time the component renders there will be exactly the same number of calls to useState in exactly the same order, so that will be fine.
I do want to point out that setting state right away in the body of the component doesn't make much sense. When the component mounts it will start rendering with the initial values from state, but then before it can finish rendering the state has already changed and it has to start over. But presumably that's just an artifact of the example, and in your real code the if would be inside a useEffect or some other practical code location.
React docs state: don’t call Hooks inside loops, conditions, or nested functions.
Alright,the following code shows the example for the above statement. I had the same issue where i needed to set the state inside of a loop, like following
const [someArray, setArray] = useState([]);
someValue.forEach((value, index) => {
setArray([...someArray, value]) //this should be avoided
});
Above thing i have achieved like this following
var temp = [];
var counter = 0;
someValue.forEach((value, index) => {
temp.push(value);
counter++;
if (counter === someValue.length) {
setArray(temp)
}
});
if you are setting a state inside the loop than each time the component re renders which you do not want to get into.
Is this code breaking rules of hooks
No Your code looks fine, as you are setting up the state only based on condition for only once when the component renders
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
So I feel like there is something small here that im missing, but don't really know what.
constructor(props) {
super();
this.state = {
developers: [],
};
}
componentDidMount() {
fetch('API').then(features => {
return features.json();
}).then(data => {
let developers = data.features.map((info) => {
let developer_info = info.properties.name
return(
<div key={info.id}>
{info.properties.name}
{info.properties.skills}
</div>
)
})
this.setState({ developers: developers});
console.log("state", this.state.developers)
console.log(this.props)
})
}
I would ideally like to call
this.state.developers.name
or this.state.developers.skills
as i need this information, but currently i am only able to save one property in the this.state or i can call out each thing. as i have done above, but its not useful, bc i can't put the info where i need it.
what am i doing wrong?
As a rule of thumb, in state you only want to store "serialisable" data. In general this means you should not store functions or recursive data structures.
A good way to check if your data is serialisable is to think if you could (or attempt to) use JSON.stringify() on it.
What you are storing here is almost certainly not serialisable, as you are storing to state complete React elements. A React element is the thing that is returned when you do <Component /> (which is the same as React.createElement(Component, ...).
So, in your case, what you should do is
let developers = data.features.map((info) => {
const developer_info = {
name: info.properties.name,
skills: info.properties.skills
}
return developer_info;
});
this.setState({ developers: developers});
So now you would have an array of plain Javascript objects in your state.
Access the updated state in callback of setState:
this.setState({ developers }, () => console.log("state", this.state.developers));
You should also store the data in state instead of the component view code (the html tags).
Access this.state.developers's properties in the component view code instead.
This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
Closed 5 years ago.
onSelectedRow(user, clickEvent){
const state = this.state;
this.state['userId'] = clickEvent.target.getAttribute(user['mta:UserId']);
this.setState(state);
console.log(user['mta:UserId']);
console.log(this.state);
}
Okay, so when I click a table-cell in my app this function gets called.
The point of it is to take the users UserId and set the state. This UserId is later on passed down to a child component and used to get specific information. The problem is that I get the correct data in the first console.log but when I then log this.
state the userId is still null for some reason. Anyone had similiar problems?
It's most probably because you're not updating the const state, but instead trying to mutate the state itself.
Also, you don't have to make a copy of a state. You can update just the field you want to update like this:
onSelectedRow(user, clickEvent) {
this.setState({
userId: clickEvent.target.getAttribute(user['mta:UserId'])
}, () => { console.log(this.state.userId) });
console.log(user['mta:UserId']);
}
Also, your console.log won't read immediate change in the state as setState is an async action.
If you really want to read it you can pass the callback to the setState which fill fire right after the state is updated, or use React's lifecycle method componentDidUpdate().