Expo react native redux with firestore (update problem)

120 Views Asked by At

I wrote an react-native application a while ago using redux in combination with a firestore DB to sync the data between multiple devices. But I'm using Expo and to build a new iOS app i have to uprade the expo sdk from 43.0 to 48.0. After the update to 48.0 the redux solution does not work properly anymore.

When I first open the app the correct data from the firestore DB is received and everything works fine. The problem is after sneding updating the DB. The app crashes because the store is afterweards undefined. But if I restart the app the changes are actually done. So the problem is somewhere in getting the data from the firestore DB while the app is running.

package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "test": "jest"
  },
  "dependencies": {
    "@react-native-async-storage/async-storage": "1.17.11",
    "@react-native-community/masked-view": "0.1.11",
    "@react-native-firebase/app": "~18.3.0",
    "@react-native-firebase/auth": "^18.3.0",
    "@react-navigation/drawer": "^5.12.9",
    "@react-navigation/native": "^5.9.8",
    "@react-navigation/stack": "^5.14.9",
    "@use-expo/font": "^2.0.0",
    "expo": "^48.0.0",
    "expo-cli": "^6.3.10",
    "expo-document-picker": "~11.2.2",
    "expo-file-system": "~15.2.2",
    "expo-font": "~11.1.1",
    "expo-screen-orientation": "~5.1.1",
    "expo-sharing": "~11.2.2",
    "expo-status-bar": "~1.4.4",
    "expo-updates": "~0.16.4",
    "firebase": "~9.6.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.71.8",
    "react-native-dialog": "^5.6.0",
    "react-native-gesture-handler": "~2.9.0",
    "react-native-modal-selector": "^2.1.0",
    "react-native-paper": "^4.9.2",
    "react-native-reanimated": "~2.14.4",
    "react-native-safe-area-context": "4.5.0",
    "react-native-screens": "~3.20.0",
    "react-native-vector-icons": "^7.1.0",
    "react-native-walkthrough-tooltip": "^1.3.0",
    "react-redux": "^8.0.0",
    "redux": "^4.1.1",
    "redux-devtools-extension": "^2.13.9",
    "redux-firestore": "^2.0.1",
    "redux-persist": "^6.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "babel-preset-expo": "^9.3.0"
  },
  "jest": {
    "preset": "react-native",
    "setupFilesAfterEnv": [
      "@testing-library/jest-native/extend-expect"
    ]
  },
  "private": true
}

store.js

import { createStore, compose  } from 'redux'
import AsyncStorage from '@react-native-async-storage/async-storage';
import { reduxFirestore, createFirestoreInstance } from 'redux-firestore';
import {persistStore, persistReducer} from 'redux-persist';

import rootReducer from '../reducers/rootReducer';

import firebase from 'firebase/compat/app';

import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/compat/database';


import {
  initializeAuth,
  getReactNativePersistence,
} from 'firebase/auth/react-native';

const persistConfig = {
    key: 'root',
    storage: AsyncStorage,
    whitelist: ['settings']
}

const firebaseConfig = {
  apiKey: "xxx,
  authDomain: "xxx",
  projectId: "xxx",
  storageBucket: "xxx",
  messagingSenderId: "xxx",
  appId: "xxx"
};


// Initialize firebase instance

const app = firebase.initializeApp(firebaseConfig);

// Initialize Cloud Firestore through Firebase
firebase.firestore();



const auth = initializeAuth(app, { persistence: getReactNativePersistence(AsyncStorage) });

// Add reduxFirestore store enhancer to store creator
const createStoreWithFirebase = compose(
    reduxFirestore(firebase), // firebase instance as first argument, rfConfig as optional second
  )(createStore);

  
  // Create store with reducers and initial state
  const initialState = {};
  const persistedReducer = persistReducer(persistConfig, rootReducer);
  const store = createStoreWithFirebase(persistedReducer, initialState);
  const persistor = persistStore(store);

export {store, persistor, auth}

rootReducer.js

import {combineReducers} from 'redux';
import settingReducer from './settingReducer'
import {firestoreReducer} from 'redux-firestore';

const rootReducer = combineReducers({
    firestore: firestoreReducer,
    settings: settingReducer,
})

export default rootReducer;

Firestore handler snippet

import { store } from "../redux/store/store";
import firebase from 'firebase/compat/app';

const addTherapistFirestore = (therapist) => {
    let therapists = store.getState().firestore.data[getLocation()].Therapists[0]
    if(therapists == undefined) {
        therapists = [];
    }
    therapists = [...therapists, therapist]
    store.firestore.set({ collection: getLocation(), doc: 'Therapists' }, { 0: therapists })
}

export {addTherapistFirestore }

Screen snippet

const NewTherapistScreen = ({route, navigation}) => {
    const [name, setName] = useState('');

    const locationName = useSelector(state => state.settings.locationName)
    const therapists = useSelector(state => state.firestore.data[locationName].Therapists[0])

    const addTherapist = (name) => {
        addTherapistFirestore({id: (therapists.length + 1).toString(), therapist: name})
    }

    return(
    <View style={{margin: 2, backgroundColor: colors.card}}>
        <Text style={styles.text}>Name</Text>
        <TextInput style={styles.input} placeholder='Name' placeholderTextColor={colors.placeholder} onChangeText={(text) => setName(text)}/>

        <TouchableOpacity style={styles.button}
        onPress={() => {
            addTherapist(name);
            navigation.goBack()}}>
            <Text style={styles.textButton}>Therapeut erstellen</Text>
        </TouchableOpacity>
    </View>
    );
}

In this example the location name, which is also handled though redux but not the firestore DB is accessbile also after the change but in the line const therapists = useSelector(state => state.firestore.data[locationName].Therapists[0]) the firestore part is undefined and everything crashes.

I also tried it with two different device at the same time and as soon as I update the DB from one device, both crash with the same problem.

On approach that I can see is to make the changes in redux and let it sync to the DB instead of makeing the changes directly to the DB. But because both devices crash this cannot be the solution since this would only affect the device where I push the data to the db. For the other device everythinbg should behave the same.

Furthermore I can see that the data is correctly changed in the DB. So the problem is the synchronization of the DB to redux but only if the app is already running since it works at a restart.

Does anyone of you have some expirience with this error/topic?

Minninnewah

0

There are 0 best solutions below