GithubHelp home page GithubHelp logo

Comments (6)

BlackGlory avatar BlackGlory commented on April 24, 2024 4

This should not be the expected behavior, see this example.

import { useMemo, useLayoutEffect, useEffect } from 'react'

let count = 0

export default function App() {
  const obj = useMemo(() => ({ id: count++ }), [])
  console.log(`render ${obj.id}`)

  useLayoutEffect(() => {
    console.log(`useLayoutEffect ${obj.id}`)
    return () => console.log(`useLayoutEffect(cleanup) ${obj.id}`)
  }, [obj])

  useEffect(() => {
    console.log(`useEffect ${obj.id}`)
    return () => console.log(`useEffect(cleanup) ${obj.id}`)
  }, [obj])

  return <></>
}

The current behavior:

render 0
render 1
useLayoutEffect 1
useEffect 1
useLayoutEffect(cleanup) 1
useEffect(cleanup) 1
useLayoutEffect 1
useEffect 1

The expected behavior:

render 0
render 1
useLayoutEffect 0
useEffect 0
useLayoutEffect(cleanup) 0
useEffect(cleanup) 0
useLayoutEffect 1
useEffect 1

This is very bad.
If your useMemo returns an AbortController whose cleanup function is controller.abort(),
then your controller.signal will be aborted at the beginning because it actually performs the cleanup function on the second controller.

from react.

Werter12 avatar Werter12 commented on April 24, 2024

@MaciejNiklasinski I think you could add these block inside the useEffect function and it will work as you expect:

  if (ref.current === null) {
    const id = map.size; //Symbol();
    const handle = { id };
    console.log(`Adding Symbol ${id} to map`);
    map.set(id, handle);
    ref.current = handle;
  }

I also noticed that in the component before first mount the mentioned code gets triggered twice. And both time ref.current is null and map add two elements. Actually, the same behavior as you mentioned. Yeah, and only in the Strict Mode

from react.

MaciejNiklasinski avatar MaciejNiklasinski commented on April 24, 2024

@Werter12 Thank you for your suggestion, unfortunately in my real use case it won't work.

I need the handle object to be created and added to the map before the function returns the first time.

export const useSubscribction = () => {
  const ref = useRef(null);
  if (ref.current === null) {
    const id = Symbol();
    const handle = { id };
    map.set(id, handle);
    ref.current = handle;
  }

  useEffect(() => () => { map.delete(ref.current.id); }, [] );
  
  // At this point before the function returns the first time I need a handle object to already exist.
  // If it is moved to the useEffect (componentDidMount equivalent part) that will not be the case.
};

from react.

catamphetamine avatar catamphetamine commented on April 24, 2024

I've also encountered this bug: in strict mode, this inside a class component will point to the second instance in both cases of componentDidMount() / componentWIllUnmount().

  • Component instance A is created
  • Component instance B is created
  • componentDidMount() is called with this being B
  • componentWillUnmount() is called with this being B
  • componentDidMount() is called with this being B

Because of that, clean-up is not possible and various "stale props" bugs occur because componentWillUnmount() performs a clean-up of the instance B which is the one that React keeps while the instance A is what React disposes of but that instance A remains "uncleaned" and its event listeners still operate.

I've submitted a separate bug report: #26467

from react.

catamphetamine avatar catamphetamine commented on April 24, 2024

@MaciejNiklasinski Have a look at my bug report: #26467
Is it the same issue? If yes then I guess the "weird" behavior is an intentional one to reveal the components that rely on doing stuff during render ("side effects").

from react.

fhucko avatar fhucko commented on April 24, 2024

I have same problem, described it in different issue #25284 (comment).

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.