What Is State?
While props are data passed to a component from outside, state is data managed inside a component. State is what makes your app interactive — when state changes, the component re-renders to reflect the new data. It's like the component's memory.
For example, a counter component's state might hold the current count. When the user taps a button, the state updates, and the screen shows the new number. Without state, your app would be static — nothing would ever change.
Using the useState Hook
The useState hook is how you add state to functional components. It returns the current state value and a function to update it.
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
function Counter() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.count}>Count: {count}</Text>
<Button title="Increment" onPress={() => setCount(count + 1)} />
<Button title="Decrement" onPress={() => setCount(count - 1)} />
<Button title="Reset" onPress={() => setCount(0)} />
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
count: { fontSize: 32, marginBottom: 20 },
});
export default Counter;
useState(0) initializes the state with 0. It returns an array with two items: the current value (count) and a setter function (setCount). Never modify the state directly — always use the setter function. When you call setCount, React Native re-renders the component with the new value.
Updating State Based on Previous State
When your new state depends on the previous state, use the functional form of the setter. This ensures you're working with the most current value.
// Correct - uses previous state
setCount(prevCount => prevCount + 1);
// May cause issues if called rapidly
setCount(count + 1);
The functional form is safer because React may batch multiple state updates together. If you use the current value directly, you might be working with stale data. Always use the functional form when the new state depends on the old state.
State with Objects and Arrays
You can store objects and arrays in state, but you need to create new references when updating them. Never mutate state directly.
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
setTodos(prevTodos => [...prevTodos, { id: Date.now(), text, done: false }]);
};
const toggleTodo = (id) => {
setTodos(prevTodos =>
prevTodos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
};
return (
<View>
{todos.map(todo => (
<Text key={todo.id} onPress={() => toggleTodo(todo.id)}>
{todo.done ? '✓' : '○'} {todo.text}
</Text>
))}
</View>
);
}
For arrays, use the spread operator (...) or map to create new arrays. For objects, spread the old object and override the properties you want to change. This immutable approach ensures React detects the change and re-renders properly.