Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
475 views
in Technique[技术] by (71.8m points)

reactjs - How does JavaScript mechanism behind react hooks work?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...