【问题标题】:How can I using state instead of setTimeout?如何使用 state 而不是 setTimeout?
【发布时间】:2020-06-15 12:04:06
【问题描述】:

我正在学习 react 并决定尝试创建一个排序可视化工具。我从冒泡排序开始,几乎成功地创建了一个基本的可视化工具。 setTimeout 是我用来应用可视化的主要函数。

我觉得在setTimeout 上进行中继并没有充分利用反应,我想尝试不同的方法,通过useState 钩子应用可视化以及在更改状态时发生的重新渲染。我了解useState 钩子是异步的,不会立即反映。

这是我的代码:

import React, { useContext, useState, useEffect } from 'react';

const NUMBER_OF_ELEMENTS = 10;

const DEFAULT_COLOR = 'black';

const randomIntFromInterval = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

const Dummy = () => {
    const [arr, setArr] = useState([]);
    const [numberOfElements, setNumberOfElements] = useState(NUMBER_OF_ELEMENTS);
    const [doneElements, setDoneElements] = useState([]);

    useEffect(() => {
        resetArray();
    }, []);

    const resetArray = () => {
        const arr1 = [];
        for(let i = 0; i < numberOfElements; i++)
        {
            arr1[i] = randomIntFromInterval(5, 100);
        }
        console.log(arr1);
        setArr(arr1);
    }

    const bubbleSort = (arr, n) => {
        let i, j, temp, swapped, delay = 1;
        for(i = 0; i < n - 1; i++) 
        {
            swapped = false;
            for(j = 0; j < n - i - 1; j++) 
            {
                createColor(j, j + 1, delay++, 'darkred');
                if(arr[j] > arr[j + 1]) 
                {
                    // swap arr[j] and arr[j+1] 
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                    createAnimation(j, j + 1, delay++);
                }
                createColor(j, j + 1, delay++, 'black');
            }
            createSingleColor(n - i - 1, delay++, 'green');

            // If no two elements were  
            // swapped by inner loop, then break 
            if(swapped === false) break;
        }

        for(let k = 0; k < n - i - 1; k++) {
            createSingleColor(k, delay++, 'green');
        }
    }

    const createAnimation = (one, two, delay) => {
        const arrayBars = document.getElementsByClassName('array-bar');
        setTimeout(() => {
            const barOneHeight = arrayBars[one].style.height;
            const barTwoHeight = arrayBars[two].style.height;
            arrayBars[two].style.height = `${barOneHeight}`;
            arrayBars[one].style.height = `${barTwoHeight}`;
        }, 250 * delay);
    }

    const createColor = (one, two, delay, color) => {
        const arrayBars = document.getElementsByClassName('array-bar');
        setTimeout(() => {
            arrayBars[two].style.backgroundColor = color;
            arrayBars[one].style.backgroundColor = color;
        }, 250 * delay); 
    }

    const createSingleColor = (index, delay, color) => {
        const arrayBars = document.getElementsByClassName('array-bar');
        setTimeout(() => {
            arrayBars[index].style.backgroundColor = color;
        }, 250 * delay); 
    }

    const handleSort = (arr) => {
        bubbleSort(arr, arr.length);
    }

    const handlerRange = (e) => {
        setNumberOfElements(e.target.value);
    }

    return (
        <div>
            <div className="array-container">
                {arr.map((value, idx) => (
                    <div className="array-bar"
                         key={idx}
                         style={{
                            backgroundColor: 'black',
                            height: `${value}px`,
                            width: `${100 / arr.length}%`,
                            display: 'inline-block',
                            margin: '0 1px'
                         }}>
                    </div>
                ))}
            </div>

            <div className="buttons-container">
                <button onClick={() => handleSort(arr)}>Sort!</button>
                <button onClick={() => resetArray()}>Reset</button>
                <button onClick={() => {
                    setDoneElements([...doneElements, 7]);
                    console.log(doneElements);}}>print</button>
            </div>
            <div className="slider-container">
                1
                <input type="range" 
                       min="1" 
                       max="100" 
                       onChange={(e) => handlerRange(e)} 
                       className="slider" 
                       id="myRange" 
                />
                100
            </div>
            {numberOfElements}

        </div>
    );
}

export default Dummy;

例如,当我尝试在 bubblesort 函数中使用 setDoneElements 时,我搞砸了可视化。

有没有办法使用钩子来应用可视化,而不是那么依赖setTimeout

【问题讨论】:

    标签: reactjs sorting react-hooks settimeout visualization


    【解决方案1】:

    找到解决办法:

    import React, { useState, useEffect } from 'react';
    const shortid = require('shortid');
    
    const randomIntFromInterval = (min, max) => {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
    
    const Dummy2 = () => {
        const [arr, setArr] = useState([]);
        const [length, setLength] = useState(10);
        const [doneElements, setDoneElements] = useState([]);
        const [compareElements, setCompareElements] = useState([]);
    
        useEffect(() => {
            generateArray();
        }, [length]);
    
        const generateArray = () => {
            setDoneElements([]);
            setCompareElements([]);
            const tempArr = [];
            for(let i = 0; i < length; i++) {
                tempArr.push(randomIntFromInterval(7, 107));
            }
            setArr([...tempArr]);
        }
    
        const handleLength = (e) => {
            setLength(e.target.value);
        }
    
        const bubbleSort = () => {
            let i, j, swapped, delay = 100;
            const tempArr = [...arr];
            const tempDoneElements = [...doneElements];
            for(i = 0; i < length - 1; i++) 
            {
                swapped = false;
                for(j = 0; j < length - i - 1; j++) 
                {
                    createColor([j, j + 1], delay, 'COMPARE');
                    delay += 100;
                    if(tempArr[j] > tempArr[j + 1]) 
                    {
                        createAnimation(tempArr, j, j + 1, delay);
                        delay += 100;
                        swapped = true;
                    }
                    createColor([], delay, 'NONE');
                    delay += 100;
                }
                tempDoneElements.push(length - i - 1);
                createColor(tempDoneElements, delay, 'DONE');
                delay += 100;
    
                // If no two elements were  
                // swapped by inner loop, then break 
                if(swapped === false) break;
            }
    
            for(let k = 0; k < length - i - 1; k++) {
                tempDoneElements.push(k);
            }
            createColor(tempDoneElements, delay, 'DONE');
            delay += 100;
        }
    
        const createAnimation = (tempArr, indexOne, indexTwo, delay) => {
            const temp = tempArr[indexOne];
            tempArr[indexOne] = tempArr[indexTwo];
            tempArr[indexTwo] = temp;
            const newArr = [...tempArr];
            setTimeout(() => {
                setArr([...newArr]);
              }, delay);
        }
    
        const createColor = (tempElements, delay, action) => {
            switch(action) {
                case 'DONE': 
                    const newDoneElements = [...tempElements];
                    setTimeout(() => {
                        setDoneElements([...newDoneElements]);
                    }, delay);
                    break;
                case 'COMPARE':
                    setTimeout(() => {
                        setCompareElements([...tempElements]);
                    }, delay);
                    break;
                default:
                    setTimeout(() => {
                        setCompareElements([]);
                    }, delay);
            }
        }
    
        const maxVal = Math.max(...arr);
        
        return (
            <div>
                <div className="array-container" style={{height: '50%'}}>
                    {arr.map((value, idx) => (
                        <div className="array-element"
                             key={shortid.generate()}
                             style={{height: `${(value * 100 / maxVal).toFixed()}%`,
                                     width: `calc(${100 / length}% - 2px)`,
                                     margin: '0 1px',
                                     display: 'inline-block',
                                     backgroundColor: compareElements.includes(idx) ? 'darkred' : 
                                                      doneElements.includes(idx) ? 'green' : 'black',
                                     color: 'white'}}
                        ></div>))
                    }
                </div>
                <div>
                    <button onClick={() => generateArray()}>New array</button>
                    <button onClick={() => bubbleSort()}>Sort</button>
                </div>
                <div className="slider-container">
                    1
                    <input type="range" 
                           min="1" 
                           max="100" 
                           onChange={(e) => handleLength(e)} 
                           className="slider" 
                           id="myRange" 
                    />
                    100
                </div>
                {length}
            </div>
        );
    }
    
    export default Dummy2;
    

    我没有弄乱 DOM,而是使用 state 来跟踪更改,因此 react 将负责更改内容。

    在排序函数中操作数组时,我们需要记住arr 是状态的一部分,因此它是不可变的。我们需要对副本进行任何更改,并在正确的时间应用更改,以便出现动画,这就是我在 createAnimation 函数中所做的。

    为了跟踪我添加到状态 doneElementscompareElements 的颜色。每次元素到达它的最终位置时,它的索引都会添加到doneElements。在任何给定时间,仅比较两个元素,因此 compareElements 将仅包含两个元素或不包含任何元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多