Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react native ref measureLayout

I am following this tutorial

https://www.youtube.com/watch?v=ZiSN9uik6OY&list=RDCMUCTcH04SRuyedaSuuQVeAcdg&start_radio=1&t=1398

The problem is when I console.log( i.ref.current), I see all value. The ap will just not start with error Undefined is not an Object inside the app.

and in reactive native console following comes up

This error is located at:
    in Tabs (at App.js:118)
    in RCTView (at View.js:34)
    in View (at App.js:91)
    in App (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)
 ERROR  TypeError: undefined is not an object (evaluating 'nativeNode._nativeTag')


below is the app.js file:

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Dimensions, Animated, FlatList, Image } from 'react-native';


const {width, height} = Dimensions.get('screen')

const images = {
  man:
    'https://images.pexels.com/photos/3147528/pexels-photo-3147528.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
  women:
    'https://images.pexels.com/photos/2552130/pexels-photo-2552130.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
  kids:
    'https://images.pexels.com/photos/5080167/pexels-photo-5080167.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
  skullcandy:
    'https://images.pexels.com/photos/5602879/pexels-photo-5602879.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
  help:
    'https://images.pexels.com/photos/6857165/pexels-photo-6857165.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
};
const data = Object.keys(images).map((i) => ({
  key: i,
  title: i,
  image: images[i],
  ref: React.createRef()
}));

const Indicator = () =>{
  return (<View  style={{
    position:'absolute',
    height:4,
    width:100,
    backgroundColor:'white',
    bottom: -10
   }}/>);
 
}

const Tab = React.forwardRef(({item}, ref) => {
  return (
    <View ref={ref}>
      <Text style={{
        color:'rgba(255, 255, 255, 0.8)', 
        fontWeight:'800', 
        fontSize:84/data.length,
        textTransform: 'uppercase' }}>{item.title}</Text>
    </View>
  );
});

const Tabs  = ({data, scrollX}) =>{
  const [measures, setMeasures] = React.useState([])
  const containerRef = React.useRef();

  React.useEffect(() => {
    let m = []
    data.forEach((i) => {
      i.ref.current.measureLayout(
        containerRef.current,
        (x, y, width, height) => {
          m.push({x, y, width, height})
          console.log(x, y, width, height)
        }
      );
        if(m.length === data.length){
          setMeasures(m)
        }
    });
  }, [])
  console.log(measures);
   return( <View style={{ position: 'absolute', top:50, width }}>
      <View style={{justifyContent:'space-evenly', flex:1, flexDirection:'row'}}>
        {
          data.map((item) => {
            return <Tab key={item.key} item={item} ref={item.ref} />
          }) 
        }
      </View>
      <Indicator/>
    </View>
  )

}


export default function App() {
  const scrollX = React.useRef(new Animated.Value(0)).current;


  return (
    <View style={styles.container}>
      <StatusBar hidden />
      <Animated.FlatList 
        data={data}
        keyExtractor={item => item.key}
        renderItem={({item}) => {
            return (<View style={{width, height}}>
              <Image 
                source={{uri: item.image}} 
                style={{flex:1, resizeMode:'cover'}} 
                />
                <View style={
                   [
                     StyleSheet.absoluteFillObject,
                     {backgroundColor: 'rgba(0,0,0, 0.3)' }
                   ]}/>
            </View>)
          }
        }
        horizontal
        showsHorizontalScrollIndicator={false}
        pagingEnabled
        onScroll={Animated.event([{nativeEvent: {contentOffset :{x: scrollX } }}],
          {useNativeDriver: false}
          )}
        bounces={false}
        />
        <Tabs scrollX={scrollX} data={data} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
}); ```

Thanks. appreciate your time reading this

like image 215
cjava Avatar asked Mar 16 '26 18:03

cjava


1 Answers

The problem is that you haven't attached containerRef to any View.

Since the ref isn't attached to a component containerRef.current evaluates to undefined, causing the logic in the useEffect to break.

So your the Tabs component should probably look more like this:

const Tabs = ({data, scrollX}) => {
  const [measures, setMeasures] = React.useState([]);
  const containerRef = React.useRef();

  React.useEffect(() => {
    let m = [];
    data.forEach((i) => {
      i.ref.current.measureLayout(
        containerRef.current,
        (x, y, width, height) => {
          m.push({x, y, width, height});
          console.log(x, y, width, height);
        },
      );
      if (m.length === data.length) {
        setMeasures(m);
      }
    });
  }, []);

  return (
    <View style={{position: 'absolute', top: 50, width}}>
      <View
        ref={containerRef}
        style={{justifyContent: 'space-evenly', flex: 1, flexDirection: 'row'}}>
        {data.map((item) => {
          return <Tab key={item.key} item={item} ref={item.ref} />;
        })}
      </View>
      <Indicator />
    </View>
  );
};
like image 108
Bas van der Linden Avatar answered Mar 19 '26 10:03

Bas van der Linden