Как сформулировать несколько функций отмены подписки из firebase в приложении Redux - PullRequest
0 голосов
/ 16 апреля 2020

в реактивном приложении-редуксе я хочу отписаться от нескольких слушателей onSnapshot (5), когда пользователь выходит из системы. Я пытался отписаться от нескольких моих слушателей, но после выхода из системы возникает ошибка:

enter image description here

Вот мое действие по выходу из системы:

export const logoutUser = (uid, role) => {

    return (dispatch) => {
        onProfileChange(uid, true);
        getConversations(uid, true);
        getAgenda(uid, role, true)
        onAccountChange(uid, true)

        return new Promise((resolve, reject) => {

            firebase
                .auth()
                .signOut()
                .then(() => {
                    dispatch({ type: types.RESET_APP });
                    console.log('Dispatching types.RESET_APP');
                    resolve();
                })
                .catch((error) => reject(error.message));
        });
    };
};

Вот действие onProfileChange (структура этого действия аналогична остальной, с условным оператором для аргумента отказа от подписки). это, очевидно, находится во внешнем файле, импортированном в компонент и сопоставленном с реквизитами

export const onProfileChange = (uid, isUnsubscribe) => {
    return (dispatch) => {
        const unsubscribe = firebase.firestore().collection('profiles').doc(uid).onSnapshot((doc) => {
            console.log('Profile: ' + JSON.stringify(doc.data()));
            dispatch({ type: types.LOAD_PROFILE, payload: doc.data() });
        });
        if ( typeof isUnsubscribe != "undefined" || isUnsubscribe == true) {
            unsubscribe()
        } 
    };
};

В конструкторе моего компонента я вызываю приведенную выше функцию следующим образом:

constructor (props) {
    super(props);
    props.onAccountChange(props.authUser.uid);
}

, затем это функция внутри того же компонента выполняется при нажатии кнопки:

logout = () => {
        this.props
            .logoutUser(this.props.authUser.uid, this.props.role)
            .then(() => {
                this.props.navigation.navigate('Login');
            })
            .catch((err) => alert(err));
    };

РЕДАКТИРОВАТЬ: набор правил Firebase:

service cloud.firestore {

  // allow only authenticated users to view database data
  match /databases/{database}/documents {
    allow read: if request.auth.uid != null
  }

  // allow only the logged in user to write their own documents
  // i.e Account data, Profile data, Messages, User-Conversations
  match /databases/{database}/documents {
    match /users/{uid} {
      allow read, write, update, delete: if request.auth.uid == uid
    }
    match/users/{uid} {
      allow update: if request.auth.uid != null 
    }
    match /profiles/{uid} {
        allow write, update, delete: if request.auth.uid == uid
    }

    // allow reading of all profile data if authenticated
    match /profiles/{uid} {
      allow read: if request.auth.uid != null
    }
    match /users/{uid} {
      allow read: if request.auth.uid != null
    }
    match /mostWanted/{docId} {
      allow read, update, create: if request.auth.uid != null
    }

    // Get multiple Docs by single owner (User-Conversations)
    match /user-conversations/{docId} {
      allow read, delete:
        if resource.data.owner == request.auth.uid
    }
    // Do the same ^ for /messages/{docId}
    // => requires 'receiver' data property to integrate
    match /messages/{docId} {
      allow create, read, update: if request.auth.uid != null
    }
    // allow read/write of user-convo's if authenticated
    match /user-conversations/{docId} {
      allow read, write, update: if request.auth.uid != null
    }    
  }
}

Почему я все еще получаю эту ошибку firebase/permission-denied, если слушатели имеют был отписан? Единственное, о чем я думаю, это установить слушателя состояния аутентификации во всех этих действиях. и когда это изменится, вызовите unSubscribe reference

Ответы [ 2 ]

0 голосов
/ 21 апреля 2020

Ваш ответ - то, что я имел в виду, когда я сказал, что ваша переменная отказа от подписки должна иметь ссылку на оригинальных слушателей, которых вы создали. Вы не можете просто создать новую подписку при выходе из системы, а затем сразу же отписаться от этого. Это не будет ничего делать со старыми, которые вы открыли ранее.

Просто передать действие отписки создателю действия? В выход из системы ButtonHandler, позвоните this.props.logoutUser(unsubscribeAccount). Если у вас есть больше, вы можете поместить их в массив и передать массив в logOutuser, и там вы можете просто отобразить массив, вызвать каждый элемент (функции отмены подписки) массива.

export const logoutUser = (unsubscribeAccount) => {
    return (dispatch) => {
        return new Promise((resolve, reject) => {
            unsubscribeAccount();
            firebase
                .auth()
                .signOut()
                .then(() => {
                    dispatch({ type: types.RESET_APP });
                    console.log('Dispatching types.RESET_APP');
                    resolve();
                })
                .catch((error) => reject(error.message));
        });
    };
};
0 голосов
/ 21 апреля 2020

После нескольких попыток я смог обойти ошибку, хотя я не в восторге от того, как это сделано, потому что он, по-видимому, загрязняет компонент. В любом случае, вот как я это сделал для всех, кто хочет добавить и отсоединить прослушиватели моментальных снимков Firestore в реактивных проектах.

У меня есть компонент выдвижного ящика, который устанавливает слушателя в его конструкторе:

imports {...}

class DrawerContentComponent extends React.Component {
    constructor (props) {
        super(props);

        this.unsubscribeAccount = firebase.firestore().collection('users').doc(props.authUser.uid).onSnapshot((doc) => {
            console.log("EXECUTING ONSNAPSHOT()...")
            if (doc.get('role') == 'Influencer') {
                onProfileChange(props.authUser.uid);
            }
        });
    }

    logout = () => {
        this.props
            .logoutUser()
            .then(() => {
                this.props.navigation.navigate('Login');
            })
            .catch((err) => alert(err));
    };

    // CALL REFERENCE TO LISTENER ON UNMOUNT
    componentWillUnmount() {
        console.log("EXECUTING COMPONENT WILL UNMOUNT")
        this.unsubscribeAccount();
    }

    < rest of component >
}

действие, выполняемое в функции компонента выхода из системы:

export const logoutUser = () => {
    return (dispatch) => {
        return new Promise((resolve, reject) => {
            firebase
                .auth()
                .signOut()
                .then(() => {
                    dispatch({ type: types.RESET_APP });
                    console.log('Dispatching types.RESET_APP');
                    resolve();
                })
                .catch((error) => reject(error.message));
        });
    };
};

Изначально я хотел, чтобы был способ вызвать одно действие (logoutUser()) и получить отписку от всех слушателей, как изначально, у меня были все слушатели установили в одном из моих файлов действий. не это не работает независимо от того, я упорно пытался.

Но что мне до сих пор любопытно, так это причина того, почему это сработало в устранении ошибки permission-denied. По моим логам c порядок выполнения таков:

  1. нажата кнопка
  2. введена функция logout() компонента
  3. она вызывает действие logoutUser()
  4. переключает навигатор обратно с навигатора ящика, и компонент ящика отключается
  5. достигнута ссылка на this.unsubscribeAccount().

Это не имеет смысла для меня, потому что действие signOut () firebase auth все еще происходит перед отпиской, поэтому имеет смысл, что временно, слушатель все еще подключен в момент изменения состояния аутентификации. и я подтвердил, что это так. ссылка на слушателя - последнее, что нужно выполнить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...