I am learning react-native
with redux
. I am getting this error (seems the store is null but where?) when I am trying to access the state with useSelector
.
Error: Cannot read properties of null (reading 'store') TypeError: Cannot read properties of null (reading 'store') at eval (react-redux.js:3:6325) at App (App.js.js:27:33
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useSelector, useDispatch, Provider } from 'react-redux';
import { createStore } from 'redux';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
const initialState = { counter: 0 };
const counterReducer = (state = initialState, action) => {
const { type, payload } = action;
if (type == 'INCREMENT') {
return { ...state, counter: state.counter++ };
}
return state;
};
const store = createStore(counterReducer);
export default function App() {
const counter = useSelector((state) => state.counter);
return (
<Provider store={store}>
<View style={styles.container}>
<TouchableOpacity onPress={useDispatch({ type: 'INCREMENT' })}>
<Text style={styles.paragraph}>{counter}</Text>
</TouchableOpacity>
<Card>
<AssetExample />
</Card>
</View>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
Link to the code: https://snack.expo.dev/@iosdose/bba0eb
App
component is trying to use the useSelector
hook outside the Redux Provider
component providing the store
object.TouchableOpacity
component's onPress
event handler is trying to directly use the useDispatch
hook.counterReducer
is mutating the counter state, i.e. state.counter++
mutates the reference.Abstract the counter
state and UI into a new component that is rendered within the Provider
component's sub-ReactTree. Refactor to correctly use the useDispatch
hook and correctly dispatch the INCREMENT
action. Update the INCREMENT
reducer case to correctly return a new state value and not mutate any of the existing state.
Example:
const initialState = { counter: 0 };
const counterReducer = (state = initialState, action) => {
const { type, payload } = action;
if (type == 'INCREMENT') {
return {
...state,
counter: state.counter + 1 // <-- don't mutate!
};
}
return state;
};
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector((state) => state.counter);
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => dispatch({ type: 'INCREMENT' })}>
<Text style={styles.paragraph}>{counter}</Text>
</TouchableOpacity>
<Card>
<AssetExample />
</Card>
</View>
);
};
export default function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
Updated Expo Snack