GithubHelp home page GithubHelp logo

Comments (7)

egonSchiele avatar egonSchiele commented on June 21, 2024 1

Hi @catamphetamine ,
You're using strict mode, and useInsertionEffect does not mount twice the way useLayoutEffect and useEffect do.

from react.

catamphetamine avatar catamphetamine commented on June 21, 2024

@egonSchiele

You're using strict mode, and useInsertionEffect does not mount twice the way useLayoutEffect and useEffect do.

Thanks, but why doesn't it though?
Don't you consider it a bug?
They're all "effect"s, so why does their behavior differ in strict mode?
That makes no sense and useInsertionEffect() isn't supposed to be anything "special":

useInsertionEffect is a version of useEffect that fires before any DOM mutations.

From the official docs:
https://beta.reactjs.org/reference/react/useInsertionEffect

So I consider the current behavior a bug.

from react.

catamphetamine avatar catamphetamine commented on June 21, 2024

Looks like in the current versions of React, the only workaround for the "strict" mode would be modifying the effect hooks like this:

import { useRef, useCallback } from 'react'

// A workaround for a React bug when `useInsertionEffect()` doesn't run twice on mount
// in "strict" mode unlike `useEffect()` and `useLayoutEffect()` do.
// https://github.com/facebook/react/issues/26320
export default function useEffectDontMountTwiceInStrictMode(useEffect, handler, dependencies) {
  if (!Array.isArray(dependencies)) {
    throw new Error('Dependencies argument must be an array')
  }

  const { onEffect } = useEffectStatus()
  const { onChange } = usePrevousValue(dependencies)

  useEffect(() => {
    const { isInitialRun } = onEffect()
    const previousDependencies = onChange(dependencies)
    if (isInitialRun || !isShallowEqualArrays(previousDependencies, dependencies)) {
      const cleanUpFunction = handler()
      if (typeof cleanUpFunction === 'function') {
        throw new Error('An effect can\'t return a clean-up function when used with `useEffectDontMountTwiceInStrictMode()` because the clean-up function won\'t behave correctly in that case')
      }
    }
  }, dependencies)
}

function useEffectStatus() {
  const hasMounted = useRef(false)

  const onEffect = useCallback(() => {
    const wasAlreadyMounted = hasMounted.current
    hasMounted.current = true
    return {
      isInitialRun: !wasAlreadyMounted
    }
  }, [])

  return {
    onEffect
  }
}

function usePrevousValue(value) {
  const prevValue = useRef(value)

  const onChange = useCallback((value) => {
    const previousValue = prevValue.current
    prevValue.current = value
    return previousValue
  }, [])

  return {
    onChange
  }
}

function isShallowEqualArrays(a, b) {
  if (a.length !== b.length) {
    return false
  }
  let i = 0
  while (i < a.length) {
    if (a[i] !== b[i]) {
      return false
    }
    i++
  }
  return true
}
import { useLayoutEffect } from 'react'

function Component() {
  useEffectDontMountTwiceInStrictMode(useLayoutEffect, handler, dependencies)
}

For example, in my case, a library uses useInsertionEffect() / useLayoutEffect() to squeeze into that tiny timeframe in order to accept some calls from child components' useLayoutEffect()s, so 1:1 calls correspondence is a requirement.

from react.

egonSchiele avatar egonSchiele commented on June 21, 2024

I think you are correct, it needs to mount twice. I am working on this bug now and the discussion is happening here #26332

from react.

catamphetamine avatar catamphetamine commented on June 21, 2024

@egonSchiele Wow, that was quick, thanks 👍

from react.

github-actions avatar github-actions commented on June 21, 2024

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

from react.

catamphetamine avatar catamphetamine commented on June 21, 2024

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.