首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自定义钩子回调只能访问它的初始状态

自定义钩子回调只能访问它的初始状态
EN

Stack Overflow用户
提问于 2021-08-31 11:15:43
回答 1查看 595关注 0票数 1

我在我的React应用程序中创建了一个自定义钩子,它将一些函数传递给挂钩所连接的Component。这些函数用于根据钩子是否认为自己是mounted来更新媒体。

但是,我遇到了一个问题,当我从钩子返回一个函数(play),然后调用该函数时,它会根据钩子的初始状态更新数据(尽管状态已经更新了很多次)。

代码语言:javascript
复制
const usePlayer = () => {
    const audioRef = useRef(__GLOBAL_AUDIO);
    const [state, setState] = useReducer((state, newState) => ({...state, ...newState}), {
        mounted: false,
        playing: false,
    });

    const play = () => ensureMounted(() => { 
        audioRef.current.play(); 
    });
    const ensureMounted = callback => {
        // This if statement will never run as this function does not 
        // seem to get any state other than the initially supplied one
        if(state.mounted){
            callback();
            return;
        }

        // ensureMounted will always skip to this portion of the function
        // despite what the current state is
        audioRef.current.src = cdn("/link/to/new/src.mp3");
        onLoad(callback);
    };

    useEffect(() => {
        // This function is tied to redux, but is irrelevant. Just know 
        // that mounted does change from true to false and vice-versa - often.
        const _mounted = checkToSeeIfMounted();
        setState({ mounted: _mounted });
    }, deps);

    return {
        playing: state.playing,
        play: play,
    };
};

显然,这段代码已经非常简化了,但我希望它仍然能传达我所面临的问题。我有一种预感,问题在于React可能是在传承一个旧的(?)引用每个重呈现上的函数,但我不确定,官方文档对于“高级”函数非常模糊,我不知道如何使用它们,或者它们是否有用。

所有的帮助都很感激,干杯。

EN

回答 1

Stack Overflow用户

发布于 2021-08-31 12:00:59

您的代码似乎像预期的那样工作。引用不存在明显的问题。(编辑:至少在你最初的问题的代码中)。

请记住,自定义hook在使用它的组件的“同一级别”工作。换句话说,就像您在组件中直接使用自定义钩子的useState一样。使您的自定义钩子‘重新呈现’的操作也将导致您的组件重新呈现。

请记住,状态更改通常是异步进行的。这有时会导致令人困惑的行为。

当您的代码第一次运行时,两个useEffect挂钩都按顺序运行。第一个useEffect将只运行一次,因为它没有依赖项(它中的hook.example引用始终是第一个引用(最终是旧的),但是它只运行一次,所以您不会遇到任何问题,除非您在回调中执行其他一些事情(比如添加事件侦听器或执行一些异步捕获),或者在useEffect运行之前调用hook.example (从而更改原始状态)。

在调用hook.example之后,继续记录数据的当前值(false),然后请求状态更新(异步),继续执行代码,并触发第二个useEffect,记录当前值(false)。最后,状态更新,您的自定义钩子‘重新呈现’导致您的组件也重新呈现。现在,第一次useEffect不触发,第二次useEffect触发是因为hook.data更改了。最后,记录新的数据值(true)。

当通过单击按钮调用hook.example时,没有问题,因为hook.example总是在那里保存最新的引用。

还请注意,良好实践要求您的第一个useEffect钩子将hook作为依赖项(然后应该在useEffect回调中执行最终的筛选逻辑),在您的示例中,向依赖项数组添加hook将导致无限循环。也许您的实际代码是不同的,但是知道这一点是很好的。

如果您需要更多的澄清,不要犹豫的评论。

代码语言:javascript
复制
const useHook = () => {
    const [data, setData] = React.useState(false);

    const example = () =>
        preCallCheck(() => {
            setData(!data);
        });

    const preCallCheck = (callback) => {
        console.log('preCallCheck()\t', data);
        callback();
    };

    return {
        data: data,
        example: example
    };
};

const Parent = () => {
    const hook = useHook();

    React.useEffect(() => {
        hook.example();
    }, []);

    React.useEffect(() => {
        console.log('useEffect()\t', hook.data);
    }, [hook.data]);

    return (
      <div>
        <h1>{'Hello, World!'}</h1>
        <button type={'button'} onClick={() => hook.example()}>{'Click Me'}</button>
      </div>
    );
};

ReactDOM.render(<Parent />, document.getElementById('root'));
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="root"></div>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68997679

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档