software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
8.95k stars 1.3k forks source link

[Reanimated] Duplicate shared tag "itemID" on the same screen #4981

Closed sezaiufuk closed 10 months ago

sezaiufuk commented 1 year ago

Description

I have FlatList items listed on my screen on my React Native app, each item gets a sharedTransitionTag with their own IDs for uniqueness, but on re-render I get this warning on console:

[Reanimated] Duplicate shared tag "itemID" on the same screen

It does not throw an error just warning but later it causes app to crash both on IOS and Android, next transition attempt gets buggy, item gets stuck on middle of the screen above everything or directly disappears, few seconds later app gets crash, what should I do ?

Steps to reproduce

  1. FlatList Items Rendered with their own sharedTransitionTags
  2. Rerendered Component
  3. Got crash

Snack or a link to a repository

*

Reanimated version

3.4.2

React Native version

0.71.6

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

None

Architecture

None

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

github-actions[bot] commented 1 year ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

github-actions[bot] commented 1 year ago

Hey! 👋

It looks like you've omitted a few important sections from the issue template.

Please complete Snack or a link to a repository section.

tjzel commented 1 year ago

Hi @ufukdev34, Shared Element Transitions are not working properly with hot-reloads (e.g. saving in VS Code as you mentioned) at the moment. Best way to develop your code is to leave the screen that contains Shared Element Tags do the hot-reload and then go to it again.

Latropos commented 1 year ago

Since this is probably a hot-reload issue I'm adding label "Close when stale"

lukebars commented 1 year ago

I'm experiencing the same issue while using the Shared Element transition example.

    "@react-navigation/native": "^6.1.7",
    "@react-navigation/native-stack": "^6.9.13",
    "react-native": "0.72.4",
    "react-native-reanimated": "^3.4.2",

Transition doesn't work, and Reanimated presents this warning:

 WARN  [Reanimated] Duplicate shared tag "sharedTag" on the same screen

It doesn't matter if it's a hot reload, a fresh metro instance, or even a rebuilt app.

OsaedYahyaCoretava commented 1 year ago

@lukebars I am facing the same issue!

tjzel commented 1 year ago

Hi @lukebars and @OsaedYahyaCoretava. I just tested it on Shared Element Transition example with the nightly version and didn't get any warnings.

Pipi144 commented 1 year ago

I'm experiencing this issue as well, when i tried to do conditional rendering for items in animated flatlist. Here is some of my code:

//*******
const DocketOrdersMainScreen = ({navigation}: Props) => {
  const {THEME_COLOR} = useDOXLETheme();
  const {
    ordersList,
    isFetchingOrderList,
    isSuccessFetchingOrderList,
    isErrorFetchingOrderList,
  } = useGetDocketOrderList({});
  const {selectedOrderStatus} = useOrderStore(
    state => ({
      selectedOrderStatus: state.selectedOrderStatus,
    }),
    shallow,
  );
  //* render list

  const renderItem = useCallback(
    (props: {item: Order; index: number}) =>
      Boolean(
        selectedOrderStatus &&
          selectedOrderStatus.statusId === props.item.status,
      ) ? (
        <OrderItem orderItem={props.item} />
      ) : null,
    [selectedOrderStatus],
  );

  const keyExtractor = useCallback(
    (item: Order, index: number) => item.orderId,
    [],
  );
  const layoutList = Layout.springify().damping(16);
return (
  {isSuccessFetchingOrderList && (
          <Animated.FlatList
            style={{flex: 1}}
            contentContainerStyle={{flexGrow: 1}}
            ListEmptyComponent={
              <DoxleEmptyPlaceholder
                headTitleText="No Orders!"
                subTitleText="Add more items to manage your work..."
                wrapperStyle={{paddingBottom: 42}}
              />
            }
            keyExtractor={keyExtractor}
            itemLayoutAnimation={layoutList}
            data={ordersList}
            extraData={selectedOrderStatus}
            renderItem={renderItem}
            initialNumToRender={14}
            maxToRenderPerBatch={4}
            updateCellsBatchingPeriod={400}
            ListFooterComponent={<OrderListFooter />}
            automaticallyAdjustContentInsets
            automaticallyAdjustKeyboardInsets
            keyboardDismissMode="interactive"
            keyboardShouldPersistTaps="handled"
            showsVerticalScrollIndicator={false}
          />
        )}
</StyledDocketOrdersMainScreen>
  );

  //********

basically when the list items get mounted again, this warning show

Pipi144 commented 1 year ago

And sometimes i also experienced the transition animation remains on the screen, even though i do a reload in flipper, the transition will still be there until i quit the app and open

Bayramito commented 1 year ago

it's n not working at all...

i just created fresh new app to test this feature, with newest versions of reanimated, navigation, screens etc...

and with the example usage code but seems like did not work at all..

    "@react-navigation/native": "^6.1.8",
    "@react-navigation/native-stack": "^6.9.14",
    "@react-navigation/stack": "^6.3.18",
    "react": "18.2.0",
    "react-native": "0.72.5",
    "react-native-gesture-handler": "^2.13.1",
    "react-native-reanimated": "^3.5.4",
    "react-native-safe-area-context": "^4.7.2",
    "react-native-screens": "^3.25.0"
diego-rangel commented 1 year ago

After so many hours, I noticed that in my case it was related to the Expo + Firebase setup and the following expo plugin:

[
  "expo-build-properties",
  {
    "ios": {
      "useFrameworks": "static"
    }
  }
]

I cannot just remove it because it's a required step to make Firebase Auth to work as described in https://rnfirebase.io/#expo-managed-workflow.

If I completely remove firebase and all firebase related plugins from the project, the shared transitions just works and the warn "Duplicate shared tag "itemID" on the same screen" was solved.

AlirezaHadjar commented 1 year ago

@diego-rangel Yeah, just realized that it has stopped working since I used use_frameworks! :linkage => :static in my Podfile. And it is a mandatory step of Firebase installation

diego-rangel commented 1 year ago

I’ve even tried changing my auth provider to another one who provides native integration via dev client and does not require this step like auth0 but I had no lucky, the shared transition again stops working

lukebars commented 1 year ago

I'm also using use_frameworks! linkage: :static, so this must be the culprit

diego-rangel commented 1 year ago

Anyone has any idea? I'd really love to have them both working together

Bayramito commented 1 year ago

+1 same here

bruno-de-queiroz commented 1 year ago

Following the solution posted: https://github.com/software-mansion/react-native-reanimated/issues/4425. I believe you can setup the following plugin:

app.plugin.js

const plugins = require('@expo/config-plugins');
const generateCode = require('@expo/config-plugins/build/utils/generateCode');
const fs = require('fs');
const path = require('path');
const data = `
  $static_framework = ['RNScreens']

  pre_install do |installer|
    Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
    installer.pod_targets.each do |pod|
      if $static_framework.include?(pod.name)
        def pod.build_type;
          Pod::BuildType.static_library
        end
      end
    end
  end
`;
const withStaticRNScreen = config => {
  return plugins.withDangerousMod(config, [
    'ios',
    async config => {
      const filePath = path.join(config.modRequest.platformProjectRoot, 'Podfile');
      const contents = fs.readFileSync(filePath, 'utf-8');
      const mergeResults = generateCode.mergeContents({
        tag: 'static-rnscreen',
        src: contents,
        newSrc: data,
        anchor: /post_install\sdo\s\|installer\|/,
        offset: 0,
        comment: '#',
      });
      if (!mergeResults.didMerge) {
        console.log(
          "ERROR: Cannot add the fix for the RNScreens to the project's ios/Podfile because it's malformed. Please report this with a copy of your project Podfile.",
        );
        return config;
      }
      fs.writeFileSync(filePath, mergeResults.contents);
      return config;
    },
  ]);
};
exports.default = withStaticRNScreen;

And use in your app.config.js/app.json

...
  "plugins": [
    ...
    './app.plugin',
    ...
  ]
...
diego-rangel commented 1 year ago

In my case using the plugin proposed by @bruno-de-queiroz solved the warning "Duplicate shared tag XXX on the same screen" but the shared transition animation still doesn't work

bruno-de-queiroz commented 1 year ago

Hi @diego-rangel, here are some versions I'm using:

    "react-native-reanimated": "~3.3.0",
    "react-native-screens": "~3.22.0",
    "react-native": "0.72.5",
    "expo": "^49.0.13",
    "expo-router": "2.0.9",
    "@react-native-firebase/app": "^18.5.0",
    "@react-native-firebase/auth": "^18.5.0",

With those, it works just as normally as before.

Bayramito commented 1 year ago

add this to your Podfile, pod update , re-build please


target 'xProject' do
// 
  $static_framework += [
    'RNScreens'
  ]

  pre_install do |installer|

    Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
      installer.pod_targets.each do |pod|
        if $static_framework.include?(pod.name)
          def pod.build_type;
          Pod::BuildType.static_library # >= 1.9
        end
      end
    end
  end

end
diego-rangel commented 1 year ago

Alright, let me try giving you a bit more details. BTW thank you @bruno-de-queiroz for the help.

This is my current relevant dependency versions:

"@react-native-firebase/app": "^18.5.0",
"@react-native-firebase/auth": "^18.5.0",
"expo": "^49.0.13",
"expo-router": "2.0.9",
"react": "18.2.0",
"react-native": "^0.72.5",
"react-native-reanimated": "~3.3.0",
"react-native-screens": "~3.22.0",

Layout code:

import React from 'react'
import { Stack } from 'expo-router'

export default function MyLayout() {
  return (
    <Stack>
      <Stack.Screen
        name="index"
        options={{ headerTitle: 'Home' }}
      />
      <Stack.Screen
        name="modal"
        options={{
          headerShown: false,
          presentation: 'transparentModal',
          animation: 'fade',
        }}
      />
    </Stack>
  )
}

ScreenA code:

import React from 'react'
import Animated from 'react-native-reanimated'
import { useRouter } from 'expo-router'
import { View } from 'tamagui'

import { Button } from '@/components/Button'

const ScreenA = () => {
  const { push } = useRouter()
  return (
    <View>
      <Animated.View
        sharedTransitionTag="any-testing-tag"
        style={{
          backgroundColor: 'red',
          height: 100,
          width: 100,
        }}
      />

      <Button onPress={() => push('/modal')}>
        Open Modal
      </Button>
    </View>
  )
}

Modal code:

import React from 'react'
import Animated from 'react-native-reanimated'
import { BlurView } from 'expo-blur'
import { useRouter } from 'expo-router'
import { View } from 'tamagui'

import { Button } from '@/components/Button'

const Modal = () => {
  const { back } = useRouter()

  return (
    <BlurView>
      <View>
        <Animated.View
          sharedTransitionTag="any-testing-tag"
          style={{
            backgroundColor: 'red',
            height: 200,
            width: 200,
          }}
        />

        <Button onPress={back}>
          Close
        </Button>
      </View>
    </BlurView>
  )
}

This is what happens: bug-repro

I have noticed one weird thing. Sometimes while editing the code with hot reload suddenly the animation works, but after a hot restart everything breaks again. Then I noticed that it happens when I change the component tree around the Animated.View that should be animating on ScreenA.

If I just wrap it with another View:

<View>
   <Animated.View
      sharedTransitionTag="any-testing-tag"
      style={{
        backgroundColor: 'red',
        height: 100,
        width: 100,
      }}
  />
</View>

and do a hot reload, the animation temporarily works until a restart:

bug-repro-2

Ajmal0197 commented 10 months ago

Getting same warning, also transition not working.

    "react-native-reanimated": "^3.6.1",
    "react-native-screens": "^3.29.0",

Podfile:

 def node_require(script)
   # Resolve script with node to allow for hoisting
   require Pod::Executable.execute_command('node', ['-p',
     "require.resolve(
       '#{script}',
       {paths: [process.argv[1]]},
     )", __dir__]).strip
 end

 node_require('react-native/scripts/react_native_pods.rb')
 node_require('react-native-permissions/scripts/setup.rb')

 # ⬇️ uncomment wanted permissions
setup_permissions([
  'Notifications'
])

platform :ios, min_ios_version_supported
prepare_react_native_project!

flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

# Add the following lines for Firebase Static Frameworks
use_frameworks! :linkage => :static
$RNFirebaseAsStaticFramework = true

use_modular_headers!

target 'RNDevLearnNew' do
  config = use_native_modules!

  # firebase
    # Your other pod dependencies
    pod 'FirebaseCoreInternal'
    pod 'FirebaseSessions'

    $RNFirebaseAnalyticsWithoutAdIdSupport=true
  # firebase

  # react-native-config
  pod 'react-native-config', :path => '../node_modules/react-native-config'
  # For extensions without React dependencies
  pod 'react-native-config/Extension', :path => '../node_modules/react-native-config'
  # react-native-config

  use_react_native!(
    :path => config[:reactNativePath],
    # Enables Flipper.
    #
    # Note that if you have use_frameworks! enabled, Flipper will not work and
    # you should disable the next line.
    # :flipper_configuration => flipper_config,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  target 'RNDevLearnNewTests' do
    inherit! :complete
    # Pods for testing
  end

  post_install do |installer|
    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false
    )
  end
end
AlirezaHadjar commented 10 months ago

@Ajmal0197 add this code below target 'RNDevLearnNew' do and above config = use_native_modules!:

pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.eql?('RNScreens')
        def pod.build_type
          Pod::BuildType.static_library
        end
      end
    end
  end
Ajmal0197 commented 10 months ago

@AlirezaHadjar Thank you it worked had to remove pods and podfile.lock and reinstall again. I hope this won't affect firebase things.

AlirezaHadjar commented 10 months ago

@Ajmal0197 No worries. since we have a condition that only applies for RNScreens, it will not affect the Firebase setup.

Ajmal0197 commented 10 months ago

@AlirezaHadjar Ok great...🫡

tjzel commented 10 months ago

Closing it since it turns out to be a duplicate of #4425.

Lobovem commented 4 months ago

@Ajmal0197 add this code below target 'RNDevLearnNew' do and above config = use_native_modules!:

pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.eql?('RNScreens')
        def pod.build_type
          Pod::BuildType.static_library
        end
      end
    end
  end

It is work for me, only was need delete Podfile.lock and pods folder

ngdbao commented 4 months ago

@Ajmal0197 add this code below target 'RNDevLearnNew' do and above config = use_native_modules!:

pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.eql?('RNScreens')
        def pod.build_type
          Pod::BuildType.static_library
        end
      end
    end
  end

It is work for me, only was need delete Podfile.lock and pods folder

It prevents warning successfully, but doesn't work for intended effect

I tried to add this in many places, but no luck 🙁

<Animated.View sharedTransitionTag='tag' style={{ borderWidth: 1, height: getSize.m(48) }} />
Lobovem commented 4 months ago

I saw bug with it, when I reload (key R) app, then don't work, but before reload it is work

timvandaatselaar commented 4 weeks ago

Does anyone have a solution that also works after reload?