> 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 in a scroll view or list.

### Detecting visibility

**SDK component:** `InView`

`InView` The component detects when an element starts appearing on the screen or disappears. When the element begins to be visible even a little, `onChanged` the handler is called and as the first argument `true` is passed. Conversely, when the element disappears from the screen, `false` is passed. `onChanged` As the handler's second argument, the element's screen visibility ratio is passed. The visibility ratio value is `0`from `1.0` between. For example `0.2`if it is passed, it means the component is visible on the screen by 20%.

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

`InView`must always `IOContext`that includes [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**

{% code collapsedlinecount="10" %}

```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;
}
```

{% endcode %}

**Parameters**

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

  The props object passed to the component.

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

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

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

  Use this option to call `the onChange` callback only once when the element becomes visible on screen for the first time.
* onLayout(event: LayoutChangeEvent) => void

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

  A callback function called when an element appears on or disappears from the screen. The first argument is the visibility state, and the second argument is the visibility ratio.

**Example**

{% code collapsedlinecount="10" %}

```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>
  );
}
```

{% endcode %}

***

### Detect list visibility

**SDK component:** `IOFlatList`

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

`InView`When used with it, you can check the visibility state of each element. The component included as a child element `InView` component `IOFlatList`detects whether an element is visible on screen through its observation feature and triggers events according to the visibility state.

**Signature**

{% code collapsedlinecount="10" %}

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

{% endcode %}

**Example**

{% code collapsedlinecount="10" %}

```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',
  },
});
```

{% endcode %}

***

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

**SDK component:** `IOScrollView`, `ImpressionArea`

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

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

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

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

Otherwise, `Used outside IOContext.Provider.`An error with that message occurs.
{% endhint %}

#### Handling when an element appears by 20% or more in a scroll view

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

The red line `100px`of `20%` is a visual representation of the point.

{% code collapsedlinecount="10" %}

```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>
  );
}
```

{% endcode %}


---

# 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.
