0

The logic I have used when registering a user is to add their details to a path in the database as well as to Firebase authentication. In theory the values would be easier to manipulate. My goal is to create a Formik form that will accept the existing value of the username of the logged in user, display that in a Text Input for the user to change then update the value in Firebase database. Can anyone help?

import React, {Component} from 'react';
import {TextInput, View, Button, StyleSheet} from 'react-native';
import {Formik} from 'formik';
import Firebase from 'firebase';
import 'firebase/database';
import 'firebase/auth';

export default class ChangeUsername extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentUsername: '',
      Username: '',
    };
  }

  getUsername() {
    const userKey = Firebase.auth().currentUser.uid;
    const userRef = Firebase.database().ref('users/' + userKey);

    userRef.once('value').then(snapshot => {
      const user = snapshot.val();
      this.setState({currentUsername: user.username});
      console.log(this.state.currentUsername);
    });
  }

  changeUsername() {
    const userKey = Firebase.auth().currentUser.uid;
    const userRef = Firebase.database().ref('users/' + userKey);
    userRef.update({
      username: this.state.Username,
    });
    console.log(this.state.Username);
  }

  componentDidMount() {
    this.getUsername();
    this.changeUsername();
  }

  render() {
    return (
      <View>
        <Formik
          initialValues={{
            username: this.state.currentUsername,
          }}
          enableReinitialize={true}
          onSubmit={this.changeUsername()}>
          {props => (
            <View>
              <TextInput
                style={style.txtInput}
                onChangeText={text => this.setState({Username: text})}
                value={this.state.currentUsername}
              />
              <Button title="Submit" onPress={props.handleSubmit} />
            </View>
          )}
        </Formik>
      </View>
    );
  }
}

I have also attempted creating the form with a React functional component as opposed to a class. What is currently happening is the Text Input remains empty and will revert back to empty everytime I try to type something in it. Plus, the username in the database will be updated to the letter I manage to type in before it disappears. I.e. I type the letter "p", the username will be updated to the string "p" in firebase database then the text input will be cleared.

anon
  • 3
  • 2
  • What doesn't work about the code that you shared? For example: when you step through the code in the debugger, which line doesn't do what you expect it to do? The clearer you can make the problem description, the more likely it is that someone can help. – Frank van Puffelen Apr 22 '20 at 15:30
  • So when I console.log(this.state.currentUsername) and console.log(Username), nothing is returned for either. currentUsername is supposed to read the existing 'username' value in the database and Username was created to obtain the value inputted by the user in the text input to then be set as the new username. Is there anything else you would need to know? – anon Apr 22 '20 at 15:45
  • I don't see any `console.log` in your original snippet. Please make sure that your question includes all the relevant code as a single minimal snippet, so that we can see how it all relates. – Frank van Puffelen Apr 22 '20 at 16:19
  • I've updated the code – anon Apr 22 '20 at 19:59
  • Calling `setState` is an asynchronous operation, so this won't work: `this.setState({currentUsername: user.username}); console.log(this.state.currentUsername);` By the time the `console.log` runs, the state may not have been updated yet. See https://stackoverflow.com/questions/41446560/react-setstate-not-updating-state for how to handle this situation correctly. – Frank van Puffelen Apr 22 '20 at 20:36

1 Answers1

0

Instead of attempting to get username directly from the database, I solved the issue but extracting it from the displayName field in Firebase authentication.

import React, {useState} from 'react';
import {TextInput, View, Button, StyleSheet} from 'react-native';
import Firebase from 'firebase';
import 'firebase/database';
import 'firebase/auth';
import {Formik} from 'formik';
import {userKey} from '../config/ReusableVariables';

export default function ChangeUsername() {
  //obtain the user and username of logged in user as objects
  const user = Firebase.auth().currentUser;
  const currentUsername = Firebase.auth().currentUser.displayName;

  //set username variable that will be changed as the existing username
  const [Username, setUsername] = useState(currentUsername);

  //function that rewrites username in firebase authentication and database
  function changeUsername(value) {
    user.updateProfile({displayName: value.username}).then(() => {
      Firebase.database()
        .ref('users/' + userKey)
        .update({username: value.username});
    });
  }
  return (
    <View>
      <Formik
        initialValues={{
          username: currentUsername,
        }}
        enableReinitialize={true}
        onSubmit={values => {
          changeUsername({
            username: Username,
            displayName: Username,
            //values in authentication and database changed to newly set Username
          });
        }}>
        {props => (
          <View>
            <TextInput
              style={style.txtInput}
              onChangeText={
                text => setUsername(text)
                //variable Username will be set to whatever is typed into this text input
              }
              value={Username}
            />
            <Button
              title="Submit"
              onPress={
                props.handleSubmit
                //links button to onSubmit function in Formik
              }
            />
          </View>
        )}
      </Formik>
    </View>
  );
}
anon
  • 3
  • 2