使用去抖动来反作用useCallback可以使用旧值,如何获取实际状态值?

我不能满足所有条件:

  1. 我需要在useCallback中使用某些功能,因为我将其设置为子组件的道具(用于防止重新渲染)
  2. 我需要使用debounce,因为我的功能是“终点”并且可以被称为〜100次/秒
  3. 去抖后,我需要获取当前值(实际值)。

我对最后一点有疑问,去抖动(1000ms)后我的值已过时。

如何使用useCallback + debounce获取当前值? (警报中的值必须与页面相同)

使用去抖动来反作用useCallback可以使用旧值,如何获取实际状态值?

//ES6 const,let
//ES6 Destructuring 
const { Component,useCallback,useState,useEffect } = React;

const SUBChildComponent = (props) => (<button onClick={props.getVal}>Getvalue with debounce</button>);

const ChildComponent = () => {
    // some unstable states
    const [someVal1,setsomeVal1] = useState(0);
    const [someVal2,setsomeVal2] = useState(0);
    const [someVal3,setsomeVal3] = useState(0);

    // some callback witch works with states AND called from subClild components
    const getVal = useCallback(_.debounce(() => {
        alert(`${someVal1}\n${someVal2}\n${someVal3}`);
    },1000),[someVal1,someVal2,someVal3]);

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setsomeVal1(someVal1 + 1),50);
        return () => clearInterval(id);
    },[someVal1]);

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setsomeVal2(someVal2 + 1),100);
        return () => clearInterval(id);
    },[someVal2]);

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setsomeVal3(someVal3 + 1),250);
        return () => clearInterval(id);
    },[someVal3]);

    return <React.Fragment><SUBChildComponent getVal={getVal}/><br/>{someVal1}<br/>{someVal2}<br/>{someVal3}
    </React.Fragment>;
};

class App extends Component {
    render() {
        return (<div><ChildComponent/></div>);
    }
}

ReactDOM.render(<App/>,document.querySelector(".container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>

<div class="container"></div>

shdzjsq 回答:使用去抖动来反作用useCallback可以使用旧值,如何获取实际状态值?

首先,您必须注意,debounce函数会在其关闭时设置其关闭状态。现在,该函数将在几秒钟后执行,届时状态将已更改。另外,每次状态更新时都会创建一个新的debounce实例,因此,如果您完全使用debounce函数onClick,它将无法正常工作,因为不同的调用将调用不同的debounce函数实例,而不是同一实例

在这种情况下,解决方案是将状态值作为防反跳函数的参数传递,而不是让它依赖于闭包。但是,它仍然使用调用去抖动的值,如下面的代码片段所示

//ES6 const,let
//ES6 Destructuring 
const { Component,useCallback,useState,useEffect } = React;

const SUBChildComponent = ({getVal,someVal1,someVal2,someVal3}) => (<button onClick={() => getVal(someVal1,someVal3)}>GetValue with debounce</button>);

const ChildComponent = () => {
    // some unstable states
    const [someVal1,setSomeVal1] = useState(0);
    const [someVal2,setSomeVal2] = useState(0);
    const [someVal3,setSomeVal3] = useState(0);

    // some callback witch works with states AND called from subClild components
    const getVal = useCallback(_.debounce((val1,val2,val3) => {
        alert(`${val1}\n${val2}\n${val3}`);
    },1000),[]); // create debounce function only once

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setSomeVal1(someVal1 + 1),50);
        return () => clearInterval(id);
    },[someVal1]);

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setSomeVal2(someVal2 + 1),100);
        return () => clearInterval(id);
    },[someVal2]);

    // some synthetic changes
    useEffect(() => {
        const id = setInterval(() => setSomeVal3(someVal3 + 1),250);
        return () => clearInterval(id);
    },[someVal3]);

    return <React.Fragment><SUBChildComponent someVal1={someVal1} someVal2={someVal2} someVal3={someVal3} getVal={getVal}/><br/>{someVal1}<br/>{someVal2}<br/>{someVal3}
    </React.Fragment>;
};

class App extends Component {
    render() {
        return (<div><ChildComponent/></div>);
    }
}

ReactDOM.render(<App/>,document.querySelector(".container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>

<div class="container"></div>

现在,另一种解决方案是保留状态引用并在反跳功能中使用它们,这是您所需要的

//ES6 const,useEffect,useRef } = React;

const SUBChildComponent = React.memo(({getVal}) => {
    console.log('child render');
    return <button onClick={() => getVal()}>GetValue with debounce</button>;
});

const ChildComponent = () => {
    // some unstable states
    const [someVal1,setSomeVal3] = useState(0);
    const someVal1Ref = useRef(someVal1);
    const someVal2Ref = useRef(someVal2);
    const someVal3Ref = useRef(someVal3);
     
    useEffect(() => {
        someVal1Ref.current = someVal1;
        someVal2Ref.current = someVal2;
        someVal3Ref.current = someVal3;
    },[someVal1,someVal3])
    
    // some callback witch works with states AND called from subClild components
    const getVal = useCallback(_.debounce(() => {
        alert(`${someVal1Ref.current}\n${someVal2Ref.current}\n${someVal3Ref.current}`);
    },[someVal3]);

    return <React.Fragment><SUBChildComponent getVal={getVal}/><br/>{someVal1}<br/>{someVal2}<br/>{someVal3}
    </React.Fragment>;
};

class App extends Component {
    render() {
        return (<div><ChildComponent/></div>);
    }
}

ReactDOM.render(<App/>,document.querySelector(".container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>

<div class="container"></div>

PS。这种实现在类组件中更容易,并且不需要任何变通,因为您不依赖于闭包

本文链接:https://www.f2er.com/2321876.html

大家都在问