Skip to main content
Jotai works perfectly with React Native out of the box. Our goal is to maintain 100% compatibility with React Native across all platforms.

Getting Started

1

Install Jotai

npm install jotai
# or
yarn add jotai
2

Create atoms

// store/atoms.ts
import { atom } from 'jotai'

export const countAtom = atom(0)
export const userAtom = atom(null)
3

Use in components

import { useAtom } from 'jotai'
import { countAtom } from './store/atoms'
import { View, Text, Button } from 'react-native'

export default function Counter() {
  const [count, setCount] = useAtom(countAtom)
  
  return (
    <View>
      <Text>Count: {count}</Text>
      <Button 
        title="Increment" 
        onPress={() => setCount(c => c + 1)} 
      />
    </View>
  )
}

No Special Configuration

Jotai atoms can be used in React Native applications with absolutely no changes from web usage. All features work identically:
  • Primitive atoms
  • Derived atoms
  • Async atoms
  • Atom utilities
  • All hooks

Persistence

For persisting state in React Native, use atomWithStorage with AsyncStorage:
import { atomWithStorage, createJSONStorage } from 'jotai/utils'
import AsyncStorage from '@react-native-async-storage/async-storage'

const storage = createJSONStorage(() => AsyncStorage)

const userAtom = atomWithStorage('user', null, storage)
const settingsAtom = atomWithStorage('settings', {}, storage)

Example with AsyncStorage

1

Install AsyncStorage

npm install @react-native-async-storage/async-storage
2

Create persistent atom

import { atomWithStorage, createJSONStorage } from 'jotai/utils'
import AsyncStorage from '@react-native-async-storage/async-storage'

const storage = createJSONStorage(() => AsyncStorage)

export const themeAtom = atomWithStorage(
  'theme',
  'light',
  storage
)
3

Use in component

import { useAtom } from 'jotai'
import { themeAtom } from './store/atoms'

export function ThemeToggle() {
  const [theme, setTheme] = useAtom(themeAtom)
  
  return (
    <Button
      title={`Switch to ${theme === 'light' ? 'dark' : 'light'}`}
      onPress={() => setTheme(theme === 'light' ? 'dark' : 'light')}
    />
  )
}

Performance

Jotai has no React Native-specific overhead. Key performance benefits:

Minimal Bundle Size

Jotai doesn’t add extra properties or methods to your data, keeping memory usage minimal.

Atomic Updates

Jotai’s atomic architecture encourages splitting logic and data, giving you precise control over every render:
// Good: Separate atoms for independent data
const nameAtom = atom('')
const ageAtom = atom(0)

function NameDisplay() {
  const [name] = useAtom(nameAtom)
  return <Text>{name}</Text> // Only re-renders when name changes
}

function AgeDisplay() {
  const [age] = useAtom(ageAtom)
  return <Text>{age}</Text> // Only re-renders when age changes
}

Optimize Renders

Keep renders fast by moving heavy computation to async actions:
const processDataAtom = atom(
  null,
  async (_get, set, rawData) => {
    // Heavy computation in async action
    const processed = await processLargeDataset(rawData)
    set(dataAtom, processed)
  }
)

Testing

Test React Native components with Jotai using @testing-library/react-native:
import { render, fireEvent } from '@testing-library/react-native'
import { Provider } from 'jotai'
import { Counter } from './Counter'

test('should increment counter', () => {
  const { getByText } = render(
    <Provider>
      <Counter />
    </Provider>
  )
  
  const counter = getByText('0')
  const incrementButton = getByText('Increment')
  
  fireEvent.press(incrementButton)
  
  expect(counter.props.children.toString()).toEqual('1')
})

Platform-Specific Atoms

Create platform-specific atoms using React Native’s Platform API:
import { Platform } from 'react-native'
import { atom } from 'jotai'

const platformAtom = atom(Platform.OS) // 'ios' | 'android' | 'web'

const platformSpecificAtom = atom((get) => {
  const platform = get(platformAtom)
  
  return platform === 'ios'
    ? 'iOS specific value'
    : 'Android specific value'
})
Jotai works well with React Navigation:
import { useAtom } from 'jotai'
import { useNavigation } from '@react-navigation/native'

const userAtom = atom(null)

function LoginButton() {
  const [user, setUser] = useAtom(userAtom)
  const navigation = useNavigation()
  
  const handleLogin = async () => {
    const user = await login()
    setUser(user)
    navigation.navigate('Home')
  }
  
  return <Button title="Login" onPress={handleLogin} />
}

Tips

Jotai works identically in React Native and web. You can share atom definitions across platforms.
Use atomWithStorage with AsyncStorage for persistent state in React Native.
Split your state into atomic pieces for optimal render performance. Each component only re-renders when its specific atoms change.
Always keep renders fast. Move heavy computation and async operations to atom write functions or separate action atoms.

Build docs developers (and LLMs) love