I am dispatching a thunk from my useEffect to populate a table when the page loads. The useEffect keeps running infintely, even though I am using an empty dependency array. Here is my code:
const Cart = (props) => {
const [didFetch, setDidFetch] = useState(false);
useEffect( () => {
async function fetchCart(){
await props.getCartItems();
setDidFetch(true);
}
fetchCart()
return setDidFetch(false)
},[]);
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Product</TableCell>
<TableCell align="right">Quantity</TableCell>
<TableCell align="right">Total Cost</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.cartItems.map((item) => (
<TableRow
key={item.product.name}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row">
{item.product.name}
</TableCell>
<TableCell align="right">{item.quantity}</TableCell>
<TableCell align="right">
{(item.quantity * item.product.price).toFixed(2)}
</TableCell>
<TableCell>
<Button onClick={() => props.removeCartItem(item.id)}>
Remove
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};
CodePudding user response:
The cleanup function of useEffect
should be an anonymous function, and you shouldn't set state variables inside it, as @windmaomao pointed out, it is a memory leak:
Suggestion
If you want to store a didFetch
flag, I would use a ref for this purpose:
import {useRef} from 'react'
const Cart = (props) => {
const fetched = useRef()
useEffect( () => {
async function fetchCart(){
const res = await props.getCartItems();
if(res) fetched.current = true
}
fetchCart()
return () => fetched.current = false
},[]);
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Product</TableCell>
<TableCell align="right">Quantity</TableCell>
<TableCell align="right">Total Cost</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.cartItems.map((item) => (
<TableRow
key={item.product.name}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row">
{item.product.name}
</TableCell>
<TableCell align="right">{item.quantity}</TableCell>
<TableCell align="right">
{(item.quantity * item.product.price).toFixed(2)}
</TableCell>
<TableCell>
<Button onClick={() => props.removeCartItem(item.id)}>
Remove
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};
CodePudding user response:
Using your existing code it would be either:
Anonymous function
const [didFetch, setDidFetch] = useState(false);
useEffect( () => {
async function fetchCart(){
await props.getCartItems();
setDidFetch(true);
}
fetchCart()
return () => {
setDidFetch(false);
};
},[]);
Named Function
const [didFetch, setDidFetch] = useState(false);
useEffect( () => {
async function fetchCart(){
await props.getCartItems();
setDidFetch(true);
}
fetchCart()
return function cleanup() {
setDidFetch(false);
};
},[]);
Here are the useEffect docs for reference: https://reactjs.org/docs/hooks-effect.html