如何运行效果取决于如果一个值增加或减少在反应?



这是对上一个问题的扩展,该问题是如何在数据发生变化时通过添加HTML类来运行效果

在本例中,我想比较新旧值。如果值增加,我可以添加一个increased类来临时添加一些CSS效果,比如2秒。同样的道理也适用于减少,但与decreased类。

让我们继续上一个答案的解决方案(为了方便参考,添加在下面)

function useHasRecentlyChanged(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;
}

如果传递给它的变量已经改变,它当前返回true,然后在timeout时间过去后返回false。我们想要改变这个函数,这样它就可以在传递给它的值最近增加或减少时进行通信。参数可以保持不变,但我们需要更改返回的接口。我们不能再用布尔值了因为我们现在有三种可能:增加,不变和减少。我将分别用正整数,零和负整数来表示因为我们可以用当前值减去前一个值来确定它是增加了还是减少了。如果减法值大于0,我们知道当前值增加了,如果减法值小于0,我们知道当前值减少了,如果减法值为0,我们知道没有变化。

increased = 1
no change = 0
decreased = -1

我们还需要添加一些东西来比较当前值和前一个值。我们可以使用useRef钩子来存储下一次渲染的值。在当前的解决方案中甚至有一个这样的例子:我们将firstRender状态存储在ref中。让我们对上面的函数进行这些更改:

function useHasRecentlyIncreasedOrDecreased(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;
}

之后,根据这个钩子返回的值添加你想要的效果。下面是一个示例:

const { useEffect, useRef, useState } = React;
const rootElement = document.getElementById('root');
function useHasRecentlyIncreasedOrDecreased(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;
}
function getRandomInt(min, max) {
const ceilMin = Math.ceil(min);
const floorMax = Math.floor(max);
return Math.floor(Math.random() * (floorMax - ceilMin + 1)) + ceilMin;
}
function ListItem({ key, children }) {
const increasedOrDecreased = useHasRecentlyIncreasedOrDecreased(children);

return (
<li key={key} className={increasedOrDecreased > 0 ? 'increased' : increasedOrDecreased < 0 ? 'decreased' : undefined}>{children}</li>
);
}
function App() {
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) => <ListItem key={index}>{item}</ListItem>)}
</ul>
);
}
ReactDOM.render(
<App />,
rootElement
);
body {
font-family: monospace;
font-size: 20px;
}
li {
margin: 5px 0;
}
.increased {
color: green;
}
.increased::after {
content: " ⬆️"
}
.decreased {
color: red;
}
.decreased::after {
content: " ⬇️"
}
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

最新更新