How To Run Effect Depending On If A Value Increases Or Decreases In React?
Solution 1:
Let's continue off the solution from the previous answer (added below for easier reference).
functionuseHasRecentlyChanged(variable, timeout = 2000) {
const firstRender = useRef(true);
const [hasRecentlyChanged, setHasRecentlyChanged] = useState(false);
useEffect(() => {
if (firstRender.current) {
return;
}
setHasRecentlyChanged(true);
setTimeout(() => {
setHasRecentlyChanged(false);
}, timeout);
}, [variable]);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
}
});
return hasRecentlyChanged;
}
It currently returns true
if the variable passed to it has changed and then returns false
after the timeout
time has elapsed. We want to change this function so that it communicates if the value passed to it has increased or decreased recently. The arguments can remain the same but we need to change the interface of the return. We can't use booleans any more because we now have three possibilities: increased, no change and decreased. I'm going to go with positive integer, zero and negative integer to represent each respectively because we can subtract the current value with the previous value to determine if it has increased or decreased. If the subtraction value is greater than 0 we know the current value has increased, if the subtraction value is less than 0 we know the current value has decreased and if the subtraction value is 0 we know there's no change.
increased = 1
no change = 0
decreased = -1
We'll also need to add something to compare the current value with the previous value. We can use the useRef
hook to store the value for the next render. There's even an example of this in the current solution: we store the firstRender
state in a ref. Let's make these changes to the above function:
functionuseHasRecentlyIncreasedOrDecreased(variable, timeout = 2000) {
const firstRender = useRef(true);
const previousValue = useRef();
const [state, setState] = useState(0);
useEffect(() => {
if (firstRender.current) {
previousValue.current = variable;
return;
}
setState(Math.min(1, Math.max(-1, variable - previousValue.current)))
previousValue.current = variable;
setTimeout(() => {
setState(0);
}, timeout);
}, [variable]);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
}
});
return state;
}
After this, add the effects you want depending on the value returned from this hook. Below is a demo:
const { useEffect, useRef, useState } = React;
const rootElement = document.getElementById('root');
functionuseHasRecentlyIncreasedOrDecreased(variable, timeout = 2000) {
const firstRender = useRef(true);
const previousValue = useRef();
const [state, setState] = useState(0);
useEffect(() => {
if (firstRender.current) {
previousValue.current = variable;
return;
}
setState(Math.min(1, Math.max(-1, variable - previousValue.current)))
previousValue.current = variable;
setTimeout(() => {
setState(0);
}, timeout);
}, [variable]);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
}
});
return state;
}
functiongetRandomInt(min, max) {
const ceilMin = Math.ceil(min);
const floorMax = Math.floor(max);
returnMath.floor(Math.random() * (floorMax - ceilMin + 1)) + ceilMin;
}
functionListItem({ key, children }) {
const increasedOrDecreased = useHasRecentlyIncreasedOrDecreased(children);
return (
<likey={key}className={increasedOrDecreased > 0 ? 'increased' : increasedOrDecreased < 0 ? 'decreased' : undefined}>{children}</li>
);
}
functionApp() {
const [items, setItems] = useState([
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
getRandomInt(0, 1000),
]);
useEffect(() => {
const intervalId = setInterval(() => {
const newItems = [...items];
const updateIndex = getRandomInt(0, items.length - 1);
newItems[updateIndex] = getRandomInt(0, 1000);
setItems(newItems);
}, 2000);
return() =>clearInterval(intervalId);
}, [...items]);
return (
<ul>
{items.map((item, index) => <ListItemkey={index}>{item}</ListItem>)}
</ul>
);
}
ReactDOM.render(
<App />,
rootElement
);
body {
font-family: monospace;
font-size: 20px;
}
li {
margin: 5px0;
}
.increased {
color: green;
}
.increased::after {
content: " ⬆️"
}
.decreased {
color: red;
}
.decreased::after {
content: " ⬇️"
}
<divid="root"></div><scriptcrossoriginsrc="https://unpkg.com/react@17/umd/react.production.min.js"></script><scriptcrossoriginsrc="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
Post a Comment for "How To Run Effect Depending On If A Value Increases Or Decreases In React?"