Изменение состояния навигационной панели после регистрации пользователя в Vue.js и Огневая база

# #javascript #firebase #vue.js #firebase-authentication

Вопрос:

В настоящее время я работаю над простым Vue.js приложение, в котором пользователь может зарегистрироваться и войти в систему. Для входа в систему и регистрации я работаю с аутентификацией Firebase. До сих пор мне удавалось заставить пользователя успешно войти в систему и изменить состояние навигационной панели: когда пользователь выходит из системы, на ней отображаются 2 кнопки: одна кнопка входа, а другая-кнопка регистрации. Когда пользователь входит в систему, эти кнопки заменяются именем пользователя и возможностью выхода. Проблема связана с опцией регистрации: сразу после заполнения формы и нажатия кнопки «Отправить» состояние навигационной панели изменяется, появляется опция «Выйти», но имя пользователя не отображается. Я хочу либо отобразить имя пользователя, а также кнопку выхода, либо чтобы приложение не входило в систему сразу после регистрации пользователя. Есть ли способ сделать это?

Скрипт формы регистрации:

 import firebase from "firebase";

export default {
  name: 'Sign-Up',
  components: {
  },
  data() {
    return {
      form: {
        errors: [],
        name: "",
        email: "",
        username: "",
        password: ""
      },
      error: null
    };
  },
  methods: {
    submit() {
      firebase
        .auth()
        .createUserWithEmailAndPassword(this.form.email, this.form.password)
        .then(data => {
          data.user
            .updateProfile({
              displayName: this.form.name
            })
            .then(() => {})
            .then(this.$router.replace({ name: "Profile" }))
        })
        .catch(err => {
          this.error = err.message;
        });
    }
  }
}
 

Навигационная панель

         <template v-if="user.loggedIn">
          <ul class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
            <li style="margin-top: 0.5em;"><router-link to="/Dashboard" class="nav-link px-2">Hello, {{user.data.displayName}}</router-link></li>
            <li><a href="#" class="nav-link px-2" @click.prevent="signOut"><button type="button" class="btn poke-secondary me-2">Sign out</button></a></li>
          </ul>
        </template>
        <template v-else>
          <div class="col-md-3 text-end px-2">
            <router-link to="/login"><button type="button" class="btn poke-secondary me-2">Login</button></router-link>
            <router-link to="/signup"><button type="button" class="btn poke-secondary">Sign Up</button></router-link>
          </div>
        </template>

<script>
import { mapGetters } from "vuex";
import firebase from "firebase/app";
export default {
  name: "Header",
  computed: {
    ...mapGetters({
      user: "user"
    })
  },
  methods: {
    signOut() {
      firebase
        .auth()
        .signOut()
        .then(() => {
          this.$router.replace({
            name: "Home"
          });
        });
    }
  }
};
</script>
 

store.js:

 import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    user: {
      loggedIn: false,
      data: null
    }
  },
  getters: {
    user(state){
      return state.user
    }
  },
  mutations: {
    SET_LOGGED_IN(state, value) {
      state.user.loggedIn = value;
    },
    SET_USER(state, data) {
      state.user.data = data;
    }
  },
  actions: {
    fetchUser({ commit }, user) {
      commit("SET_LOGGED_IN", user !== null);
      if (user) {
        commit("SET_USER", {
          displayName: user.displayName,
          email: user.email
        });
      } else {
        commit("SET_USER", null);
      }
    }
  }
});
 

Комментарии:

1. Вероятно, вы захотите вернуть обещание, которое будет выполнено, когда пользовательские данные будут полностью доступны. Ответ Firebase является асинхронным, поэтому он может быть недоступен не сразу.

Ответ №1:

Я хочу либо отобразить имя пользователя, а также кнопку выхода, либо чтобы приложение не входило в систему сразу после регистрации пользователя. Есть ли способ сделать это?

Как объясняется в документе, с createUserWithEmailAndPassword() помощью метода «при успешном создании учетной записи пользователя этот пользователь также войдет в ваше приложение».

Таким образом, невозможно избежать входа пользователя в систему «сразу после регистрации пользователя». Ваша проблема заключается в том updateProfile() , что метод асинхронен: перед обновлением возникает небольшая задержка displayName . Вы должны справиться с этим случаем, например, отображая Hello, {{user.data.displayName}} строку и кнопку «Выйти» только в том случае, если displayName она не равна нулю.

Ответ №2:

Как объяснил @Renaud, пользователь войдет в систему сразу после createUserWithEmailAndPassword разрешения метода, отображая этот div только тогда, когда displayName он не равен нулю, что может быть сделано v-if="user.data.displayName !== null" .

Альтернативой было бы использовать облачную функцию для создания новых пользователей, если вы действительно не хотите такой задержки при отображении имени пользователя. Поскольку пользователи создаются с помощью пакета SDK администратора в облачной функции, они не будут входить в систему на клиенте. Простая вызываемая функция для того же будет:

 exports.createNewUser = functions.https.onCall((data, context) => {
  const {email, password, displayName} = data
  
  return admin.auth().createUser({ email, password, displayName }).then((userRecord) => {
    console.log('Successfully created new user:', userRecord.uid);
    return {data: userRecord.uid}
  }) 
});
 

Эта функция создаст нового пользователя с предоставленными учетными данными и именем пользователя. Вы можете вызвать эту функцию из своего приложения Vue следующим образом:

 methods: {
  submit() {
    const createUser = firebase.functions().httpsCallable('createNewUser');
    createNewUser({ 
      email: this.form.email, 
      password: this.form.password,
      displayName: this.form.name
    }).then((result) => {
      const result = result.data;

      // Manually sign in user now
      // signInWithEmailAndPassword(this.form.email, this.form.password)
    });
  }
}