skip to Main Content

Despite the short title line, I have a few interrelated questions about the sample below, borrowed from React official docs. I have trimmed down the original sample a bit.

On the very first App render (when the page loads for the first time), the usePointerPosition hook registers a pointermove listener.

The useEffect in the body of usePointerPosition doesn’t run yet.

The <Dot> JSX is returned from App with a position of {0, 0}.

Question: What happens when I move the mouse? Which code triggers the render: The usePointerPosition hook, or the App component?

My possibly incorrect and incomplete understanding is:

  1. Mouse motion triggers the handleMove listener.

  2. This listener updates the state position in the usePointerPosition hook.

  3. Question: Since position is a state private to the usePointerPosition hook, why would it cause its parent, App, to re-render, which is clearly re-rendering because I do see red Dot move on the screen?

  4. I can see that the private state position is being returned to the usePointerPosition hook’s parent, App. But because pos1 in App, which stores the current mouse position, isn’t a state in App and merely a local variable, why should App re-render itself as I move the mouse?

  5. Question: In general, is some custom non-GUI hook, useXyz

    a. that only holds private state by using useState in its body;

    b. that doesn’t interact with its parent via callbacks passed to it
    via props; and

    c. that has no useEffects in its body

… capable of triggering a render of its parent component?

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

export default function App() {
    const pos1 = usePointerPosition()
    const pos2 = useDelayedValue(pos1, 100)

    return (
        <>
            <Dot position={pos1} opacity={1} />
        </>
    )
}

function usePointerPosition() {
    const [position, setPosition] = useState({ x: 0, y: 0 })
    useEffect(() => {
        function handleMove(e) {
            setPosition({ x: e.clientX, y: e.clientY })
        }
        window.addEventListener('pointermove', handleMove)
        return () => window.removeEventListener('pointermove', handleMove)
    }, [])
    return position
}

function useDelayedValue(value, delay) {
    // TODO: Implement this Hook

    return value
}

function Dot({ position, opacity }) {
    return (
        <div
            style={{
                position: 'absolute',
                backgroundColor: 'pink',
                borderRadius: '50%',
                opacity,
                transform: `translate(${position.x}px, ${position.y}px)`,
                pointerEvents: 'none',
                left: -20,
                top: -20,
                width: 40,
                height: 40
            }}
        />
    )
}

2

Answers


  1. The essence of hooks is side effect hanging on the fiber node.

    So when you call useState, it create a side effect node and hang on the fiber node of App, call setPosition will re-render App

    Login or Signup to reply.
  2. Question: Since position is a state private to the usePointerPosition hook, why would it cause its parent, App, to re-render, which is clearly re-rendering because I do see red Dot move on the screen?

    Answer: Position is a state inside the hook but you need to think it as way to connect hook state with the component that use the hook (in this case App) so all the life cycle is connected (if the hook state changes it’s going to trigger the update in the component that is using that hook)

    if not it wouldn’t make sense having or using hooks

    Question: I can see that the private state position is being returned to the usePointerPosition hook’s parent, App. But because pos1 in App, which stores the current mouse position, isn’t a state in App and merely a local variable, why should App re-render itself as I move the mouse?

    Answer: It’s a variable that is holding the state provided by the hook and each time a setState is triggered it triggers the react life cycle in the component that is using the hook

    Question: In general, is some custom non-GUI hook, useXyz…

    a. that only holds private state by using useState in its body;

    b. that doesn’t interact with its parent via callbacks passed to it via props; and

    c. that has no useEffects in its body

    Answer: Hooks can do whatever you want, think about it as a piece of code that you can reuse and will be part of the component that is calling it (triggering it’s life cycle) (even further you should be able to copy your hook code and paste it in the consumer component and it should still work)

    A little of historical context of hooks

    Prev to hooks the only way to add reusable logic was creating a wrapper component that wraps the component that will use that logic (in this example a creating a wrapper of <App>) these components had state and pass them as a props to <App>, but that old way to do that was confusing and implies to create components only to add reusable logic (that commonly didn’t generate new UI-JSX-HTML)

    Custom Hooks are made to keep the components simple and still use reusable logic through the components that need that logic

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search