首页 > 解决方案 > How to use setTimeout to make a list item wait for some time to restore its original color after a click?

问题描述

I have list items, clicking a list item should turn it red, i want every clicked item to wait for 3000ms to restore its black color again, this is my code

my trial is to use setTimeout in useEffect and setting all red fields to false but this didn't work, especially i need to make every red item to wait 3000ms from turning red to turn black again

The first item to click turn to black after 3000ms correctly, but after that items going black faster!!

  const App = () => {
        const items = [
            {
                name: 'mark',
                id: 1,
                red: false
            },
            {
                name: 'peter',
                id: 2,
                red: false
            },
            {
                name: 'john',
                id: 3,
                red: false
            }
        ]

        const [names, setNames] = useState(items);

        const turnItemRed= (id) => {
            setNames(
                names.map(i =>  i.id === id ? {...i, red: true} : i))
        }

     // this doesn't work
     useEffect(() => {
         setTimeout(() => {
             setNames( prev => prev.map( i => ({...i, red: false})))
         }, 3000)
     })

        return (
            <div class="items-cont">
                <ul class="items">
                    {
                        names.map(i => {
                            return (
                                <Item
                                    item={i}
                                    turnItemRed={turnItemRed}
                                />
                            )
                        })
                    }
                </ul>
            </div>
        )
    }

    const Item = ({ item, ...props }) => {
        const { turnItemRed } = props;
        return (
            <li
                className={`${item.red ? 'red' : ''}`}
                onClick={() => {
                    turnItemRed(item.id)
                }}
            >
                {item.name}
            </li>
        )
    }
    ReactDOM.render(<App />, document.getElementById('root'))

CSS:

.red {
     color: red
  }

标签: javascriptreactjs

解决方案


首先,您useEffect每 3 秒运行一次,这意味着您的组件每 3 秒重新渲染一次,而没有 UI 实际更新。

useEffect(() => {
  setTimeout(() => {
    setNames( prev => prev.map( i => ({...i, red: false})))
  }, 3000)
})

您需要更改您的useEffect以仅在names更改时运行。还要确保它仅在某些名称的red属性设置为 `true 时运行。

useEffect(() => {
  if (names.some(item => item.red)) {
    setTimeout(() => {
      setNames(prev => prev.map(i => ({ ...i, red: false })));
    }, 3000);
  }
}, [names]);

推荐阅读