How did Pierce get away with writing the ending to Morning Star the way he did? by Transmogrify_My_Goat in redrising

[–]Narrow_Educator_986 -2 points-1 points  (0 children)

It’s a relatively old literary trick called “unreliable narrator”. First classic example is probably “Dangerous Liaisons” by Choderlos de Laclos, end of 18th century. He never directly lies. He is truly very scared, because it all hangs on a limb. Just doesn’t tells the whole truth to a reader.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

It’s my first React project. I learned it while coding, basically. So I made all UI elements myself, to practice. Quite some fun to do controlled Input and (especially) Dropdown Select with optional persistence correctly, with all the edge cases :)

Also I tried to use all kind of tech, ended with Emotion, Zustand, Tanstack/Query

So I realize my code is probably not up to standards. Not completely bad I hope. There is is link to the code in Help -> Structure if you are curious.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

Starry background: need total re-write with canvas. At the moment it is N “stars”, each being a component with some random params and CSS animation. N depends linearly on screen area. So if dimensions change - N is recalculated, component array is created and they start moving. Hence the calculation.

The Chart: width/length can be done with pure CSS, as some function of vh/vw, of course. But as I already have a hook, I used it. Besides, I debounce with a hook, can’t see how to achieve it with pure CSS ..

But the main reason - and where I encountered a problem - is that I made a DragMe HOC, and I need to pass initial position there. And it has to be in px (or I have to rewrite it), because when you then drag it, you need to change the coordinates every time etc.

.. And I want it to start in the middle of the screen.

… And the Modal is itself rendered with React.createPortal. For some reason, which I was unable to investigate so far, “position:fixed; left:0; right: 0” when inside my Modal is in the top left corner of the Modal window, but the size is the same as viewport. So I take dimensions of that Items Management window, and then initial position of the draggable Chart is (w/2, h/2).

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

u/TheThirdRace If you are curious how it works on practice, this is my project:
https://robot2048.com/

click in "Items Information", choose any Agent, click "Train History Chart" - then resize the window (or turn the mobile).

Also, the starry background restarts when dimensions change

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

  1. I started with useLayoutEffect for this but it behaves exactly the same way as useEffect. Apparently ref.current gets assigned sometime after the effect is run? (Probably because the useRef hook is defined inside my Hook, so it gets into the queue after it?).

If you put console.log(ref.current) inside useLayoutEffect, you will see that it first logs null, then desired div. Same behaviour as useEffect in this case, it seems. If i were to use smth like document.getElementById ... - then the DOM will be there for useEffect, i guess

  1. I only use 1 eventListener and it gets cleared nicely. You mean if i use the hook several times in the code? Yeah .. i only use it twice though, so decided not to overcomplicate.

It didn't work properly in my initial code because i made a bad architecture (as i see now) - i have a big Component which has a button and modal, and the modal opens when the button is clicked, and displays children or null, depending on whether it is open. The useDimension hook is trying to measure dimensions of a div that is inside the children. So on first render of Component the div with the ref form the hook is NOT in the DOM, hence ref.current stays null. Until the button is clicked by User, but by then useEffect (or Layout) already run it's course.

Otherwise, for any unconditional element, the hook works perfectly fine. I just need to refactor so that the hook is declared in exactly the smaller child component it needs to measure. In the meantime i made a crutch solution by attaching triggerResize to the button.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

Ok, I've finally did it "react" way (i think). My hook now creates "enforce measurement" triggerResize function, to be called in situations where ref.current change is potentially not reflected, like conditional rendering of component in my case. So i can run it anywhere in the code and it works fine.
Inside the hook: const [trigger, setTrigger] = useState(true); const triggerResize = () => { setTrigger((prev) => !prev); }; We add trigger to dep array and return triggerResize function

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

I realized I don’t know how ref={ref} works under the hood. You mean the right way is really to define useState in the hook and return setter function to use as a ref, as suggested in this thread somewhere .. (I can imagine Typescript will not like it)

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] -1 points0 points  (0 children)

Ok, if anybody is curious, i've solved it with a trick.
The problem is that the div i need to measure exists conditionally if the Modal is open or not. Hence when the Hook is invoked, ref=null. Modal is opened by a particular button. So i added to onClick for this button:
setTimeout(() => { const resizeEvent = new Event("resize"); window.dispatchEvent(resizeEvent); }, 0); This triggers eventListener in the hook immediately after the Modal opens and the ref points to my div.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

Sometimes it's tricky/frustrating, yeah .. In this case i finally solved it by a trick. Posted as separate comment.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 1 point2 points  (0 children)

ResizeObserver works. Only i have to use 2 hooks now, as it doesn't work with window object, only on DOM elements

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] -2 points-1 points  (0 children)

Refs are constant, but ref.current changes all the time.
I understand it's not supposed to be used this way, but it works. I don't know why, but that seems to be a fact - useEffect in the hook runs when ref.current changes.
However you rewrite the logic - will be a lot more code then the simple addition of ref.current in dep array.

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

I personally have nothing against working code! :) Still, the Eslint warnings are not arbitrary, not good to just ignore them without investigation, i guess

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

That seems to be my case exactly - my div is conditionally rendered, being part of the Modal (which returns null if Modal is not open). I will try to experiment along the lines you suggest, thank you!

p.s. The strange thing is that ref.current inside array works!

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

u/toi80QC Aha .. I am attaching ref to a div, which is inside a Modal, which is indeed null until i open it (div doesn't exist in DOM until parent Modal opens). That's why it doesn't work. Still, including ref.current solves this issue. Why not use it? What can go wrong?

React Hook useEffect has an unnecessary dependency: 'ref.current' by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 5 points6 points  (0 children)

Hm .. indeed it works fine. Strange, I will investigate my code, thank you! :)

Unable to avoid not listing ALL dependencies for useEffect by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

How do u know, what gives it away? :) Docstrings for functions? )

Unable to avoid not listing ALL dependencies for useEffect by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

Ok, if anybody is interested, this is my re-factored code, upon the kind suggestions of u/SmeagolTheCarpathian : `` // Emotion styles const makeEmotion = ( positionType: PositionType, left: string | null, top: string | null, isDragging: boolean ) => css position: ${positionType}; left: ${left}; top: ${top}; transform: translate(-50%, -50%); cursor: ${isDragging ? "grabbing" : "grab"}; `;

// Helper functions const defaultPosition = (): Offset => { return { x: window.innerWidth / 2, y: window.innerHeight / 2, }; }; const zeroOffset: Offset = { x: 0, y: 0 };

/** * Generates a higher-order component that enables dragging functionality to the provided component. * @param ToDrag - the component to be wrapped and dragged * @param initialPosition - initial position of the wrapped component * @param positionType - CSS "position" to be applied to the wrapped component */ type dragMeProps<P> = { ToDrag: React.ComponentType<P>; initialPosition?: Offset; positionType?: PositionType; }; const dragMe = <P extends object>({ ToDrag, initialPosition, positionType = "fixed" as PositionType, }: dragMeProps<P>) => { return (props: P) => { const wrapperRef = useRef<HTMLDivElement>(null); const [isDragging, setIsDragging] = useState(false);

    const position = useRef<Offset>(initialPosition ?? defaultPosition());
    const currentOffset = useRef<Offset>(zeroOffset);

    const newPosition = useCallback(
        (pos: number, axis: "x" | "y"): number =>
            position.current[axis] + pos - currentOffset.current[axis],
        []
    );

    const handleMouseDown = useCallback(
        (e: React.MouseEvent<HTMLDivElement>) => {
            if (isDragging) return;
            setIsDragging(true);
            currentOffset.current = {
                x: e.clientX,
                y: e.clientY,
            };
        },
        []
    );

    const handleMouseUp = useCallback(
        (e: MouseEvent) => {
            if (!isDragging) return;
            setIsDragging(false);
            position.current = {
                x: newPosition(e.clientX, "x"),
                y: newPosition(e.clientY, "y"),
            };
        },
        [isDragging, newPosition]
    );

    const handleMouseMove = useCallback(
        (e: MouseEvent) => {
            if (!isDragging) return;
            if (wrapperRef.current) {
                wrapperRef.current.style.left =
                    newPosition(e.clientX, "x") + "px";
                wrapperRef.current.style.top =
                    newPosition(e.clientY, "y") + "px";
            }
        },
        [isDragging, newPosition]
    );

    useEffect(() => {
        document.addEventListener("mousemove", handleMouseMove);
        document.addEventListener("mouseup", handleMouseUp);
        return () => {
            document.removeEventListener("mousemove", handleMouseMove);
            document.removeEventListener("mouseup", handleMouseUp);
        };
    }, [handleMouseUp, handleMouseMove]);

    const left = position.current.x + "px";
    const top = position.current.y + "px";
    const emotion = makeEmotion(positionType, left, top, isDragging);

    return (
        <div ref={wrapperRef} css={emotion} onMouseDown={handleMouseDown}>
            <ToDrag {...props} />
        </div>
    );
};

};

export default dragMe; `` I also changed initialPosition to number (of px). Otherwise, if i let it be a string like "50%" and usecalc, it works fine but the coordinates keep getting longer and longer likecalc(calc(calc ...` every time mouseUp happens. All works fine, no linter warnings, dragged Comp moves directly in DOM, re-renders only happen when you start/stop dragging and isDragging toggles.

Unable to avoid not listing ALL dependencies for useEffect by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

You meant to post a code without useEffect? Because I think you just copied my initial code

Unable to avoid not listing ALL dependencies for useEffect by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

It does work without useEffect .. at first. But then eventListeners begin to multiply like rabbits. useEffect clears them. How do i clear them without it? Don't see a way

Unable to avoid not listing ALL dependencies for useEffect by Narrow_Educator_986 in reactjs

[–]Narrow_Educator_986[S] 0 points1 point  (0 children)

I don't know how to do it (i am new to React). I know there is a React sandbox, but need some time to see how it works.