1

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

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
maddy
  • 4,001
  • 8
  • 42
  • 65

1 Answers1

2

Issues

  • The App component is trying to use the useSelector hook outside the Redux Provider component providing the store object.
  • The TouchableOpacity component's onPress event handler is trying to directly use the useDispatch hook.
  • The counterReducer is mutating the counter state, i.e. state.counter++ mutates the reference.

Solution

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

Drew Reese
  • 165,259
  • 14
  • 153
  • 181