> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-en/react-native/impression.md).

# Exposure detection

You can detect whether a specific element is visible on the screen in a scroll view or list.

### Detect visibility

**SDK components:** `InView`

`InView` This component detects when an element starts appearing on the screen or disappears. As soon as the element becomes even slightly visible on the screen, `onChanged` the handler is called and `true` is passed as the first argument. Conversely, when the element disappears from the screen, `false` is passed. `onChanged` The element's screen visibility ratio is passed as the handler's second argument. The visibility ratio value is `0`in `1.0` between `0.2`For example, if

{% hint style="info" %}
**Note**

`InView`must always be used `IOContext`with [IOScrollView](#scroll-impression-area) or [IOFlatList](#%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%85%B8%EC%B6%9C-%EA%B0%90%EC%A7%80%ED%95%98%EA%B8%B0) inside. If `IOContext` used outside `IOProviderMissingError`occurs.
{% endhint %}

**Signature**

```typescript
class InView<T = ViewProps> extends PureComponent<InViewProps<T>> {
  static contextType: import('react').Context<IOContextValue>;
  static defaultProps: Partial<InViewProps>;
  context: undefined | IOContextValue;
  mounted: boolean;
  protected element: Element;
  protected instance: undefined | ObserverInstance;
  protected view: any;
  constructor(props: InViewProps<T>);
  componentDidMount(): void;
  componentWillUnmount(): void;
  protected handleChange: (inView: boolean, areaThreshold: number) => void;
  protected handleRef: (ref: any) => void;
  protected handleLayout: (event: LayoutChangeEvent) => void;
  measure: (...args: any) => void;
  measureInWindow: (...args: any) => void;
  measureLayout: (...args: any) => void;
  setNativeProps: (...args: any) => void;
  focus: (...args: any) => void;
  blur: (...args: any) => void;
  render(): import('react/jsx-runtime').JSX.Element | null;
}
```

**Parameters**

* **props** · Required · `Object`

  The props object passed to the component.

  * **props.children** · Required · `React.ReactNode`

    The child components rendered beneath the component.
* **prop.asReact.ComponentType** · `View`

  Specifies the component to actually render. The default is [View](https://reactnative.dev/docs/view) the component.
* **triggerOnce boolean** · `false`

  Only once when the element first appears on the screen `onChange` use this option to call the callback.
* onLayout(event: LayoutChangeEvent) => void

  A callback function invoked when the layout changes.
* onChange(inView: boolean, areaThreshold: number) => void

  A callback function invoked when the element appears or disappears on the screen. The first argument is whether it is visible, and the second argument is the visibility ratio.

**Example**

```tsx
import { LayoutChangeEvent, View, Text, Dimensions } from 'react-native';
import { InView, IOScrollView } from '@granite-js/react-native';

function InViewExample() {
  const handleLayout = (event: LayoutChangeEvent) => {
    console.log('Layout changed', event.nativeEvent.layout);
  };

  const handleChange = (inView: boolean, areaThreshold: number) => {
    if (inView) {
      console.log(`${areaThreshold * 100}% visible on screen`);
    } else {
      console.log('Not visible on screen');
    }
  };

  return (
    <IOScrollView>
      <View style={{ height: HEIGHT, width: '100%', backgroundColor: 'blue' }}>
        <Text style={{ color: 'white' }}>Please scroll down</Text>
      </View>
      <InView onLayout={handleLayout} onChange={handleChange}>
        <View style={{ width: 100, height: 300, backgroundColor: 'yellow' }}>
          <View
            style={{
              position: 'absolute',
              top: 30,
              width: 100,
              height: 1,
              borderWidth: 1,
            }}
          >
            <Text style={{ position: 'absolute', top: 0 }}>10% point</Text>
          </View>
        </View>
      </InView>
    </IOScrollView>
  );
}
```

***

### Detect list visibility

**SDK components:** `IOFlatList`

`IOFlatList`is a component that has added Intersection Observer functionality to detect whether a specific element appears on or disappears from the screen while scrolling. `FlatList` component. With this component, you can easily check and handle whether each item in the list appears on the screen.

`InView`If used with `InView` the component `IOFlatList`can detect whether an element is visible on the screen through its observation feature and trigger events according to their visibility state.

**Signature**

```typescript
IOFlatList: typeof IOFlatListFunction;
```

**Example**

```tsx
import { ReactNode, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { InView, IOFlatList } from '@granite-js/react-native';

const mockData = Array.from({ length: 30 }, (_, i) => ({ key: String(i) }));

function FlatListPage() {
  return <IOFlatList data={mockData} renderItem={({ item }) => <InViewItem>{item.key}</InViewItem>} />;
}

function InViewItem({ children }: { children: ReactNode }) {
  const [visible, setVisible] = useState(false);

  return (
    <InView onChange={setVisible}>
      <View style={styles.item}>
        <Text>{children}</Text>
        <Text>{visible ? 'visible' : ''}</Text>
      </View>
    </InView>
  );
}

const styles = StyleSheet.create({
  item: {
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#ddd',
  },
});
```

***

### Detect scroll area visibility <a href="#scroll-impression-area" id="scroll-impression-area"></a>

**SDK components:** `IOScrollView`, `ImpressionArea`

[`IOScrollView`](#scroll-impression-area)and [`ImpressionArea`](#scroll-impression-area)Using it, you can check whether an element is visible on the screen within a scroll view. When a specific element appears on the screen by a certain percentage or more, `onImpressionStart` the callback is called.

[`ImpressionArea`](#scroll-impression-area)the `areaThreshold` when you set a value, if the element becomes visible by at least the set percentage, `onImpressionStart` the callback is called.

{% hint style="info" %}
**`IOScrollView` can only be used inside**

[`ImpressionArea`](#scroll-impression-area)must always be used [`IOScrollView`](#scroll-impression-area) must be inside.

Otherwise, `Used outside IOContext.Provider.`an error occurs.
{% endhint %}

#### Handling when an element appears at least 20% in a scroll view

The following code is an example where an element with a height `100px`of [`IOScrollView`](#scroll-impression-area)in `20%`or more appears`onImpressionStart`and the callback is called.

The red line `100px`the `20%` is an example that visually marks the

```tsx{14,18,22-27,37-38}
import { createRoute, ImpressionArea, IOScrollView } from '@granite-js/react-native';
import { ReactNode } from 'react';
import { Alert, Text, View } from 'react-native';

export const Route = createRoute('/image', {
  component: Image,
});

/* Dummy content for scrolling */
const dummies = new Array(10).fill(undefined);

/** 20% point */
const AREA_THRESHOLD = 0.2; // [!code focus]

function Image() {
  return (
    <IOScrollView> // [!code focus]
      {dummies.map((_, index) => {
        return <DummyContent key={index} text={10 - index} />;
      })}
      <ImpressionArea // [!code focus]
        areaThreshold={AREA_THRESHOLD} // [!code focus]
        onImpressionStart={() => { // [!code focus]
          Alert.alert('Impression Start'); // [!code focus]
        }} // [!code focus]
      > // [!code focus]
        <View
          style={{
            width: '100%',
            height: 100,
            backgroundColor: 'blue',
          }}
        >
          <DebugLine areaThreshold={AREA_THRESHOLD} />
        </View>
      </ImpressionArea> // [!code focus]
    </IOScrollView> // [!code focus]
  );
}

/** Debug component that visually displays the ratio */
function DebugLine({ areaThreshold }: { areaThreshold: number }) {
  return (
    <View
      style={{
        position: 'absolute',
        top: `${areaThreshold * 100}%`,
        width: '100%',
        height: 1,
        backgroundColor: 'red',
      }}
    />
  );
}

/** Dummy area */
function DummyContent({ text }: { text: ReactNode }) {
  return (
    <View
      style={{
        width: '100%',
        height: 100,
        borderWidth: 1,
      }}
    >
      <Text>{text}</Text>
    </View>
  );
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-en/react-native/impression.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
