Reputation: 343
My situation is this:
export default function Component({ navigation }) {
const [ item, setItem ] = useState([]);
useEffect(() => {
AsyncStorage.getItem('someItem')
.then(data => JSON.parse(data))
.then(jsonData => {
setItem(jsonData);
})
.catch(error => {});
}, [item]);
The problem is that useEffect seems to be called in a loop, even when "item" doesn't change. If I remove item from the dependencies array, it gets called once only and when item changes the component does not re-render. Is there a solution?
Solved like this:
export default function Component({ navigation }) {
const [ item, setItem ] = useState([]);
const [ update, setUpdate ] = useState(false);
const handleUpdate = () => {
setUpdate(!update);
}
useEffect(() => {
AsyncStorage.getItem('someItem')
.then(data => JSON.parse(data))
.then(jsonData => {
setItem(jsonData);
})
.catch(error => {});
}, [update]);
And then calling handleUpdate (or passing it to a child component and letting the child call it) when I want to update item's state.
Upvotes: 2
Views: 989
Reputation: 7935
The issue is the same described in this post. When you use an object as a dependency, useEffect
thinks it's different on every render. Since you use an array, which is an object, you get the infinite loop. Let's say your state variable was instead a primitive type like a string or a number, then it would not keep rendering as useEffect
would be able to figure out that the value has not changed.
So, a possible solution in your specific case, because there is a JSON string being returned, could be using that JSON string as a parallel state variable to check for changes.
Consider something like this:
const simulateCall = () => Promise.resolve('["ds","1234sd","dsad","das"]')
export default function App() {
const [state, setArrayState] = React.useState([])
const [stringState, setStringState] = React.useState('')
React.useEffect(() => {
simulateCall()
.then(data => {
setStringState(data);
setArrayState(JSON.parse(data));
})
.catch(error => console.log(error));
}, [stringState]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{state.map((item, i) => <div key={i}>{item}</div>)}
</div>
);
}
Upvotes: 1
Reputation: 303
You have an infinite loop:
The second argument you send to useEffect()
is an array of dependencies. Every time one of these dependencies change - the first argument to useEffect()
which is a callback will be invoked. So here you do:
Every time item
changes - run code that changes item
(because the callback sets value with setItem
)
notice: useEffect will also invoke the callback sent to it once at first.
Upvotes: 4