0

I'm getting a stragne error in TypeScript SafeAreaView component. I crated other refs for WebView and it doesn't fail, only seems to fail when assigned to the SafeAreaView component.

import { useRef, MutableRefObject } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';
...
...
const topSafeAreaViewRef = useRef(null);
...
...
<SafeAreaView ref={topSafeAreaViewRef} style={styles.container} edges={['top', 'right', 'left']} >

TS2322: Type '{ children: Element; ref: MutableRefObject; style: { flex: number; backgroundColor: any; }; edges: ("top" | "right" | "left")[]; }' is not assignable to type 'IntrinsicAttributes & ViewProps & { children?: ReactNode; mode?: "padding" | "margin" | undefined; edges?: readonly Edge[] | undefined; }'.   Property 'ref' does not exist on type 'IntrinsicAttributes & ViewProps & { children?: ReactNode; mode?: "padding" | "margin" | undefined; edges?: readonly Edge[] | undefined; }'.

I need ref because I need to set setNativeProps on an external function

const handleOnLoadEnd = (
    syntheticEvent: WebViewNavigationEvent | WebViewErrorEvent,
    topSafeAreaViewRef: MutableRefObject<any>,
) => {
  topSafeAreaViewRef.current.setNativeProps({
    style:{
      backgroundColor: Constants?.manifest?.extra?.webViewBackground,
    }
  });

};
razor7
  • 2,165
  • 2
  • 19
  • 32

3 Answers3

2

The react-native-safe-area-context's SafeAreaView component doesn't support ref prop.

If you need the ref to calculate width, height, etc., you can try a workaround like this (Untested):

import { useRef } from 'react';
import { View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

function App() {
  const ref = useRef();
  const insets = useSafeAreaInsets();

  return (
    <View
      ref={ref}
      style={{
        paddingTop: insets.top,
        paddingLeft: insets.left,
        paddingBottom: insets.bottom,
        paddingRight: insets.right,
      }}
    />
  );
}
Yaman KATBY
  • 1,814
  • 10
  • 24
0

SafeAreaView is the preferred way to consume insets. This is a regular View with insets applied as extra padding or margin. It offers better performance by applying insets natively and avoids flickers that can happen with the other JS based consumers.

SafeAreaView is a regular View component with the safe area insets applied as padding or margin.

Padding or margin styles are added to the insets, for example style={{paddingTop: 10}} on a SafeAreaView that has insets of 20 will result in a top padding of 30.

Example:

import { SafeAreaView } from 'react-native-safe-area-context';

function SomeComponent() {
  return (
    <SafeAreaView style={{ flex: 1, backgroundColor: 'red' }}>
      <View style={{ flex: 1, backgroundColor: 'blue' }} />
    </SafeAreaView>
  );
}

Edges:

Optional, array of top, right, bottom, and left. Defaults to all.

Sets the edges to apply the safe area insets to.

For example if you don't want insets to apply to the top edge because the view does not touch the top of the screen you can use:

<SafeAreaView edges={['right', 'bottom', 'left']} />

For further Details or Documentation you can check Here

You should remove useRef() because useRef is not Sported in SafeAreaView.

Talha Akbar
  • 462
  • 3
  • 15
0

In my experimentation it seems like the ref actually does work. The SafeAreaView passes all of its props down to the underlying View component. But it doesn't use forwardRef, so it seems like it shouldn't work.

Expo Snack -- the background will turn red when the WebView has loaded (on iOS).

If it does what you want and it's just a TypeScript error, you can always use // @ts-ignore. It's not an ideal solution but it's probably the easiest.


I need ref because I need to set setNativeProps on an external function

I would recommend trying to structure your components such that you can control the style via props and don't need to use refs or setNativeProps. I'm not sure of the relationship between your WebView and your SafeAreaView, but try something like this:

interface ComponentWithWebViewProps {
  setStyle: (style: ViewStyle) => void;
}

const ComponentWithWebView = ({ setStyle }: ComponentWithWebViewProps) => {
  return (
    <WebView
      source={{
        uri: 'https://stackoverflow.com/questions/70848728/safeareaview-ref-generates-a-typescript-error/',
      }}
      onLoadEnd={() =>
        setStyle({
          backgroundColor: 'red',
        })
      }
      style={{ flex: 1 }}
    />
  );
};

const ParentComponent = () => {
  // These are the extra/override styles that we are adding.
  const [customStyle, setCustomStyle] = React.useState<ViewStyle>({});
  return (
    <SafeAreaView
      // Can pass multiple styles in an array
      style={[styles.container, customStyle]}
      edges={['top', 'right', 'left']}>
      <Text>Hello, World</Text>
      <ComponentWithWebView setStyle={setCustomStyle} />
    </SafeAreaView>
  );
};

export default function App() {
  return (
    <SafeAreaProvider>
      <ParentComponent />
    </SafeAreaProvider>
  );
}

Expo Snack

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102