react-native-scrollable-tab-view icon indicating copy to clipboard operation
react-native-scrollable-tab-view copied to clipboard

tabContainer but no owner was set.

Open ArunKumarVallal99 opened this issue 2 years ago • 2 comments

Error: Element ref was specified as a string (tabContainer) but no owner was set. This could happen for one of the following reasons:

  1. You may be adding a ref to a function component
  2. You may be adding a ref to a component that was not created inside a component's render method
  3. You have multiple copies of React loaded See https://reactjs.org/link/refs-must-have-owner for more information.

This error is located at: in AndroidHorizontalScrollContentView (at ScrollView.js:1107) in AndroidHorizontalScrollView (at ScrollView.js:1238) in ScrollView (at ScrollView.js:1264) in ScrollView (at ScrollableTabBar.js:171) in RCTView (at View.js:34) in View (at ScrollableTabBar.js:167) in ScrollableTabBar (at drList.js:2506) in RCTView (at View.js:34) in View (at react-native-scrollable-tab-view/index.js:396) in ScrollableTabView (at drList.js:2504) in RCTView (at View.js:34) in View (at drList.js:2493) in RCTView (at View.js:34) in View (at SafeAreaView.js:41) in SafeAreaView (at AppView.js:12) in AppView (at drList.js:2492) in DrList (created by Connect(DrList)) in Connect(DrList) (at tab3.js:75) in RCTView (at View.js:34) in View (at tab3.js:49) in RCTView (at View.js:34) in View (at SafeAreaView.js:41) in SafeAreaView (at tab3.js:47) in Tab3 (created by Connect(Tab3)) in Connect(Tab3) (created by SceneView) in SceneView (created by TabNavigationView) in RCTView (at View.js:34) in View (created by ResourceSavingScene) in RCTView (at View.js:34) in View (created by ResourceSavingScene) in ResourceSavingScene (created by TabNavigationView) in RCTView (at View.js:34) in View (at src/index.native.tsx:145) in ScreenContainer (created by TabNavigationView) in RCTView (at View.js:34) in View (created by TabNavigationView) in TabNavigationView (created by NavigationView) in NavigationView (created by Navigator) in Navigator (created by NavigationContainer) in NavigationContainer (at home.js:163) in RCTView (at View.js:34) in View (at home.js:157) in Home (created by Connect(Home)) in Connect(Home) (created by SceneView) in SceneView (created by CardContainer) in RCTView (at View.js:34) in View (created by CardContainer) in RCTView (at View.js:34) in View (created by CardContainer) in RCTView (at View.js:34) in View in CardSheet (created by Card) in RCTView (at View.js:34) in View (at createAnimatedComponent.js:217) in AnimatedComponent (at createAnimatedComponent.js:278) in AnimatedComponentWrapper (created by PanGestureHandler) in PanGestureHandler (created by PanGestureHandler) in PanGestureHandler (created by Card) in RCTView (at View.js:34) in View (at createAnimatedComponent.js:217) in AnimatedComponent (at createAnimatedComponent.js:278) in AnimatedComponentWrapper (created by Card) in RCTView (at View.js:34) in View (created by Card) in Card (created by CardContainer) in CardContainer (created by CardStack) in RCTView (at View.js:34) in View (created by MaybeScreen) in MaybeScreen (created by CardStack) in RCTView (at View.js:34) in View (created by MaybeScreenContainer) in MaybeScreenContainer (created by CardStack) in CardStack in KeyboardManager (created by SafeAreaInsetsContext) in SafeAreaProviderCompat (created by StackView) in RCTView (at View.js:34) in View (at GestureHandlerRootView.android.tsx:21) in GestureHandlerRootView (created by StackView) in StackView (created by StackView) in StackView in Unknown (created by Navigator) in Navigator (created by NavigationContainer) in NavigationContainer (created by SceneView) in SceneView (created by CardContainer) in RCTView (at View.js:34) in View (created by CardContainer) in RCTView (at View.js:34) in View (created by CardContainer) in RCTView (at View.js:34) in View in CardSheet (created by Card) in RCTView (at View.js:34) in View (at createAnimatedComponent.js:217) in AnimatedComponent (at createAnimatedComponent.js:278) in AnimatedComponentWrapper (created by PanGestureHandler) in PanGestureHandler (created by PanGestureHandler) in PanGestureHandler (created by Card) in RCTView (at View.js:34) in View (at createAnimatedComponent.js:217) in AnimatedComponent (at createAnimatedComponent.js:278) in AnimatedComponentWrapper (created by Card) in RCTView (at View.js:34) in View (created by Card) in Card (created by CardContainer) in CardContainer (created by CardStack) in RCTView (at View.js:34) in View (created by MaybeScreen) in MaybeScreen (created by CardStack) in RCTView (at View.js:34) in View (created by MaybeScreenContainer) in MaybeScreenContainer (created by CardStack) in CardStack in KeyboardManager (created by SafeAreaInsetsContext) in RNCSafeAreaProvider (at SafeAreaContext.tsx:76) in SafeAreaProvider (created by SafeAreaInsetsContext) in SafeAreaProviderCompat (created by StackView) in GestureHandlerRootView (at GestureHandlerRootView.android.tsx:26) in GestureHandlerRootView (created by StackView) in StackView (created by StackView) in StackView in Unknown (created by Navigator) in Navigator (created by NavigationContainer) in NavigationContainer (created by SceneView) in SceneView (created by SwitchView) in SwitchView (created by Navigator) in Navigator (created by NavigationContainer) in NavigationContainer (at App.js:21) in Provider (at App.js:20) in App (at CodePush.js:585) in CodePushComponent (at renderApplication.js:47) in RCTView (at View.js:34) in View (at AppContainer.js:107) in RCTView (at View.js:34) in View (at AppContainer.js:134) in AppContainer (at renderApplication.js:40)

I am using the latest react-native-scrollable-tab-view

ArunKumarVallal99 avatar Jun 30 '22 05:06 ArunKumarVallal99

replace the source code by the following node_modules/@react-native-community/viewpager.js `/**

  • Copyright (c) Facebook, Inc. and its affiliates.
  • This source code is licensed under the MIT license found in the
  • LICENSE file in the root directory of this source tree.
  • @format
  • @flow strict-local */

'use strict';

import type { PageScrollEvent, PageScrollStateChangedEvent, PageSelectedEvent, ViewPagerProps, } from './types';

const React = require('react'); const ReactNative = require('react-native');

const {Platform, UIManager} = ReactNative;

const dismissKeyboard = require('react-native/Libraries/Utilities/dismissKeyboard');

import {childrenWithOverriddenStyle} from './utils';

const NativeViewPager = require('./ViewPagerNativeComponent');

const VIEW_PAGER_REF = 'viewPager'; const VIEW_MANAGER_NAME = 'RNCViewPager';

function getViewManagerConfig(viewManagerName) { if (!UIManager.getViewManagerConfig) { // react-native <= 0.57 return UIManager[viewManagerName]; } return UIManager.getViewManagerConfig(viewManagerName); }

/**

  • Container that allows to flip left and right between child views. Each
  • child view of the ViewPager will be treated as a separate page
  • and will be stretched to fill the ViewPager.
  • It is important all children are <View>s and not composite components.
  • You can set style properties like padding or backgroundColor for each
  • child. It is also important that each child have a key prop.
  • Example:
  • render: function() {
  • return (
  • <ViewPager
    
  •   style={styles.viewPager}
    
  •   initialPage={0}>
    
  •   <View style={styles.pageStyle} key="1">
    
  •     <Text>First page</Text>
    
  •   </View>
    
  •   <View style={styles.pageStyle} key="2">
    
  •     <Text>Second page</Text>
    
  •   </View>
    
  • </ViewPager>
    
  • );
  • }
  • ...
  • var styles = {
  • ...
  • viewPager: {
  • flex: 1
    
  • },
  • pageStyle: {
  • alignItems: 'center',
    
  • padding: 20,
    
  • }
  • }

*/

class ViewPager extends React.Component<ViewPagerProps> { componentDidMount() { // On iOS we do it directly on the native side if (Platform.OS === 'android') { if (this.props.initialPage != null) { this.setPageWithoutAnimation(this.props.initialPage); } } }

/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found

  • when making Flow check .android.js files. */ getInnerViewNode = (): ReactComponent => { return this.pageView.getInnerViewNode(); };

_onPageScroll = (e: PageScrollEvent) => { if (this.props.onPageScroll) { this.props.onPageScroll(e); } // Not implemented on iOS yet if (Platform.OS === 'android') { if (this.props.keyboardDismissMode === 'on-drag') { dismissKeyboard(); } } };

_onPageScrollStateChanged = (e: PageScrollStateChangedEvent) => { if (this.props.onPageScrollStateChanged) { this.props.onPageScrollStateChanged(e); } };

_onPageSelected = (e: PageSelectedEvent) => { if (this.props.onPageSelected) { this.props.onPageSelected(e); } };

/**

  • A helper function to scroll to a specific page in the ViewPager.
  • The transition between pages will be animated. */ setPage = (selectedPage: number) => { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), getViewManagerConfig(VIEW_MANAGER_NAME).Commands.setPage, [selectedPage], ); };

/**

  • A helper function to scroll to a specific page in the ViewPager.
  • The transition between pages will not be animated. */ setPageWithoutAnimation = (selectedPage: number) => { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), getViewManagerConfig(VIEW_MANAGER_NAME).Commands.setPageWithoutAnimation, [selectedPage], ); };

render() { return ( <NativeViewPager {...this.props} ref={pageView=>this.pageView=pageView} style={this.props.style} onPageScroll={this._onPageScroll} onPageScrollStateChanged={this._onPageScrollStateChanged} onPageSelected={this._onPageSelected} children={childrenWithOverriddenStyle(this.props.children)} /> ); } }

module.exports = ViewPager; scrollabletabBar.jsconst React = require('react'); const { ViewPropTypes } = ReactNative = require('react-native'); const PropTypes = require('prop-types'); const createReactClass = require('create-react-class'); const { View, Animated, StyleSheet, ScrollView, Text, Platform, Dimensions, } = ReactNative; const Button = require('./Button');

const WINDOW_WIDTH = Dimensions.get('window').width;

const ScrollableTabBar = createReactClass({ propTypes: { goToPage: PropTypes.func, activeTab: PropTypes.number, tabs: PropTypes.array, backgroundColor: PropTypes.string, activeTextColor: PropTypes.string, inactiveTextColor: PropTypes.string, scrollOffset: PropTypes.number, style: ViewPropTypes.style, tabStyle: ViewPropTypes.style, tabsContainerStyle: ViewPropTypes.style, textStyle: Text.propTypes.style, renderTab: PropTypes.func, underlineStyle: ViewPropTypes.style, onScroll: PropTypes.func, },

getDefaultProps() { return { scrollOffset: 52, activeTextColor: 'navy', inactiveTextColor: 'black', backgroundColor: null, style: {}, tabStyle: {}, tabsContainerStyle: {}, underlineStyle: {}, }; },

getInitialState() { this._tabsMeasurements = []; return { _leftTabUnderline: new Animated.Value(0), _widthTabUnderline: new Animated.Value(0), _containerWidth: null, }; },

componentDidMount() { this.props.scrollValue.addListener(this.updateView); },

updateView(offset) { const position = Math.floor(offset.value); const pageOffset = offset.value % 1; const tabCount = this.props.tabs.length; const lastTabPosition = tabCount - 1;

if (tabCount === 0 || offset.value < 0 || offset.value > lastTabPosition) {
  return;
}

if (this.necessarilyMeasurementsCompleted(position, position === lastTabPosition)) {
  this.updateTabPanel(position, pageOffset);
  this.updateTabUnderline(position, pageOffset, tabCount);
}

},

necessarilyMeasurementsCompleted(position, isLastTab) { return this._tabsMeasurements[position] && (isLastTab || this._tabsMeasurements[position + 1]) && this._tabContainerMeasurements && this._containerMeasurements; },

updateTabPanel(position, pageOffset) { const containerWidth = this._containerMeasurements.width; const tabWidth = this._tabsMeasurements[position].width; const nextTabMeasurements = this._tabsMeasurements[position + 1]; const nextTabWidth = nextTabMeasurements && nextTabMeasurements.width || 0; const tabOffset = this._tabsMeasurements[position].left; const absolutePageOffset = pageOffset * tabWidth; let newScrollX = tabOffset + absolutePageOffset;

// center tab and smooth tab change (for when tabWidth changes a lot between two tabs)
newScrollX -= (containerWidth - (1 - pageOffset) * tabWidth - pageOffset * nextTabWidth) / 2;
newScrollX = newScrollX >= 0 ? newScrollX : 0;

if (Platform.OS === 'android') {
  this._scrollView.scrollTo({x: newScrollX, y: 0, animated: false, });
} else {
  const rightBoundScroll = this._tabContainerMeasurements.width - (this._containerMeasurements.width);
  newScrollX = newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX;
  this._scrollView.scrollTo({x: newScrollX, y: 0, animated: false, });
}

},

updateTabUnderline(position, pageOffset, tabCount) { const lineLeft = this._tabsMeasurements[position].left; const lineRight = this._tabsMeasurements[position].right;

if (position < tabCount - 1) {
  const nextTabLeft = this._tabsMeasurements[position + 1].left;
  const nextTabRight = this._tabsMeasurements[position + 1].right;

  const newLineLeft = (pageOffset * nextTabLeft + (1 - pageOffset) * lineLeft);
  const newLineRight = (pageOffset * nextTabRight + (1 - pageOffset) * lineRight);

  this.state._leftTabUnderline.setValue(newLineLeft);
  this.state._widthTabUnderline.setValue(newLineRight - newLineLeft);
} else {
  this.state._leftTabUnderline.setValue(lineLeft);
  this.state._widthTabUnderline.setValue(lineRight - lineLeft);
}

},

renderTab(name, page, isTabActive, onPressHandler, onLayoutHandler) { const { activeTextColor, inactiveTextColor, textStyle, } = this.props; const textColor = isTabActive ? activeTextColor : inactiveTextColor; const fontWeight = isTabActive ? 'bold' : 'normal';

return <Button
  key={`${name}_${page}`}
  accessible={true}
  accessibilityLabel={name}
  accessibilityTraits='button'
  onPress={() => onPressHandler(page)}
  onLayout={onLayoutHandler}
>
  <View style={[styles.tab, this.props.tabStyle, ]}>
    <Text style={[{color: textColor, fontWeight, }, textStyle, ]}>
      {name}
    </Text>
  </View>
</Button>;

},

measureTab(page, event) { const { x, width, height, } = event.nativeEvent.layout; this._tabsMeasurements[page] = {left: x, right: x + width, width, height, }; this.updateView({value: this.props.scrollValue.__getValue(), }); },

render() { const tabUnderlineStyle = { position: 'absolute', height: 4, backgroundColor: 'navy', bottom: 0, };

const dynamicTabUnderline = {
  left: this.state._leftTabUnderline,
  width: this.state._widthTabUnderline,
};

return <View
  style={[styles.container, {backgroundColor: this.props.backgroundColor, }, this.props.style, ]}
  onLayout={this.onContainerLayout}
>
  <ScrollView
    ref={(scrollView) => { this._scrollView = scrollView; }}
    horizontal={true}
    showsHorizontalScrollIndicator={false}
    showsVerticalScrollIndicator={false}
    directionalLockEnabled={true}
    bounces={false}
    scrollsToTop={false}
  >
    <View
      style={[styles.tabs, {width: this.state._containerWidth, }, this.props.tabsContainerStyle, ]}
      // ref={'tabContainer'}
      onLayout={this.onTabContainerLayout}
    >
      {this.props.tabs.map((name, page) => {
        const isTabActive = this.props.activeTab === page;
        const renderTab = this.props.renderTab || this.renderTab;
        return renderTab(name, page, isTabActive, this.props.goToPage, this.measureTab.bind(this, page));
      })}
      <Animated.View style={[tabUnderlineStyle, dynamicTabUnderline, this.props.underlineStyle, ]} />
    </View>
  </ScrollView>
</View>;

},

componentDidUpdate(prevProps) { // If the tabs change, force the width of the tabs container to be recalculated if (JSON.stringify(prevProps.tabs) !== JSON.stringify(this.props.tabs) && this.state._containerWidth) { this.setState({ _containerWidth: null, }); } },

onTabContainerLayout(e) { this._tabContainerMeasurements = e.nativeEvent.layout; let width = this._tabContainerMeasurements.width; if (width < WINDOW_WIDTH) { width = WINDOW_WIDTH; } this.setState({ _containerWidth: width, }); this.updateView({value: this.props.scrollValue.__getValue(), }); },

onContainerLayout(e) { this._containerMeasurements = e.nativeEvent.layout; this.updateView({value: this.props.scrollValue.__getValue(), }); }, });

module.exports = ScrollableTabBar;

const styles = StyleSheet.create({ tab: { height: 49, alignItems: 'center', justifyContent: 'center', paddingLeft: 20, paddingRight: 20, }, container: { height: 50, borderWidth: 1, borderTopWidth: 0, borderLeftWidth: 0, borderRightWidth: 0, borderColor: '#ccc', }, tabs: { flexDirection: 'row', justifyContent: 'space-around', }, }); `

bitting304 avatar Sep 19 '22 01:09 bitting304

1 node_modules/@react-native-community/js/viewpager.js line 96 getInnerViewNode = (): ReactComponent => { return this.pageView.getInnerViewNode(); }; line 152 ref={pageView=>this.pageView=pageView}

2 scrollabletabBar.js line 182 //ref={'tabContainer'}

bitting304 avatar Sep 19 '22 01:09 bitting304