react hooks 背后的 JavaScript 机制是如何工作的? [英] How does JavaScript mechanism behind react hooks work?

查看:18
本文介绍了react hooks 背后的 JavaScript 机制是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与使 React 钩子成为可能的 Javascript 机制有关.

React 最近的开发允许我们创建钩子,即.对于 React 状态,在简单的函数中,如:

函数应用(){const [someVar, setSomeVar] = useState('someVarDefaultValue');返回 (

setSomeVar('newValue')}>{someVar}

);}

钩子 useState 返回一个带有访问器和修改器的数组,我们在 App 函数中通过数组分解来使用它们.

所以在引擎盖下,钩子看起来像(只是一个伪代码):

function useState(defaultValue) {让值 = 默认值;函数 setValue(val) {值 = val;}返回 [值,设置值];}

当您在 JS 中尝试这种方法时,它不起作用 - 如果您在某处使用 setValue,从数组分解的值将不会更新.即使您使用 value 作为对象,而不是原始 defaultValue.

我的问题是钩子机制在JS中是如何工作的?

从我在 React 中看到的 源代码 它使用了 reducer 函数和 Flow 类型检查.代码很难让我理解大局.

这个问题不是关于如何在 React 中编写自定义钩子.

在这个问题中回答的 React 状态管理上下文中钩子如何在幕后工作也不是问题:React Hooks - 引擎盖下发生了什么?

解决方案

状态值必须存储在 useState 函数之外,在组件实例的某些内部表示中,以便它返回跨调用的持久结果.此外,设置该值必须导致在它被调用的组件上重新渲染:

//useState 必须引用它被调用的组件:让上下文;函数使用状态(默认值){//在组件外部调用 useState 将不起作用,因为它需要上下文:if(!context) throw new Error("只能在渲染内部调用");//仅在尚未渲染的情况下初始化上下文(否则它将在重新渲染时重新设置值)如果(!上下文.值)context.value = defaultValue;//在 setValue 中记住要访问的上下文让 memoizedContext = 上下文;函数 setValue(val) {memoizedContext.value = val;//重新渲染,以便调用 useState 将返回新值内部渲染(memoizedContext);}返回 [context.value, setValue];}//一个非常简化的 React 挂载逻辑:函数内部渲染(组件){上下文 = 组件;组件渲染();上下文 = 空;}//一个非常简化的组件var 组件 = {使成为() {const [值,更新] = useState("it");控制台日志(值);setTimeout(更新,1000,有效!");}};内部渲染(组件);

然后当 setValue 被调用时,组件重新渲染,useState 将再次被调用,并且新值将被返回.

上面的例子非常简化,这里有一些 React 做的不同的事情:

(1) 状态不存储在上下文属性"中;而是在一个链表中.每当调用 useState 时,链表都会前进到下一个节点.这就是为什么你不应该在分支/循环中使用钩子.

(2) setState 函数 get 被缓存,每次都返回相同的引用.

(3) 重新渲染不是同步发生的.

My question relates to Javascript mechanisms that make react hooks possible.

Recent development in React allows us to create hooks, ie. for React state, within as simple function like:

function App () {
  const [someVar, setSomeVar] = useState('someVarDefaultValue');
  return (
    <div 
      onClick={() => setSomeVar('newValue')}>{someVar}
    </div>
  );
}

The hook useState returns an array with an accessor and a mutator, and we use them by array decomposition inside our App function.

So under the hood, the hook looks something like (just a pseudocode):

function useState(defaultValue) {
  let value = defaultValue;

  function setValue(val) {
    value = val;
  }

  return [value, setValue];
}

When you try this approach in JS it won't work - value decomposed from array will not update if you use setValue somewhere. Even if you use the value as an object, not a primitive defaultValue.

My question is how does hook mechanism work in JS?

From what I've seen in React sourcecode it uses reducer function and type-checking with Flow. The code is tricky to follow for me to understand the big picture.

This question is not about how to write custom hooks in React.

It's also not question how hooks work under the hood in context of React state management answered in this question: React Hooks - What's happening under the hood?

解决方案

The state value has to be stored outside of the useState function, in some internal representation of the component instance, so that it returns persistent results across calls. Additionally setting the value has to cause a rerender on the component it gets called in:

     // useState must have a reference to the component it was called in:
     let context;

     function useState(defaultValue) {
       // Calling useState outside of a component won't work as it needs the context:
       if(!context) throw new Error("Can only be called inside render");
       // Only initialize the context if it wasn't rendered yet (otherwise it would re set the value on a rerender)
       if(!context.value)
        context.value = defaultValue;
       // Memoize the context to be accessed in setValue
       let memoizedContext = context;
       function setValue(val) {
          memoizedContext.value = val;
          // Rerender, so that calling useState will return the new value
          internalRender(memoizedContext);
       }

      return [context.value, setValue];
     }

    // A very simplified React mounting logic:
    function internalRender(component) {
       context = component;
       component.render();
       context = null;
    }

     

     // A very simplified component
     var component = {
      render() {
        const [value, update] = useState("it");
        console.log(value);
        setTimeout(update, 1000, "works!");
      }
    };

    internalRender(component);

Then when setValue gets called, the component rerenders, useState will get called again, and the new value will get returned.

The upper example is very simplified, here's a few things that React does differently:

(1) The state is not stored in a "context property" but rather in a linked list. Whenever useState is called, the linked list advances to the next node. That's why you should not use hooks in branches / loops.

(2) The setState function get's cached and the same reference gets returned each time.

(3) Rerendering does not happen synchronously.

这篇关于react hooks 背后的 JavaScript 机制是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆