4

I have a login screen with 2 fields email & password it works fine, but if the user inputs into either field, then presses the back button to go to the previous screen, then goes back to the login screen, the screen should be reset and blank but it contains the previous user input.

How can I clear/reset the user input i.e (state/props) when the user presses the back button and the screen closes. I'm using redux thunk, React Navigation 3

enter image description here

Here is my code for the login screen.

LoginScreen

class LoginScreen extends Component {
    constructor(props) {
    super(props);
    this.unsubscriber = null;
}

componentWillUnmount(): void {
    if (this.unsubscriber) {
    this.unsubscriber();
    }
}

onEmailChange(text) {
    this.props.emailChanged(text);
}

onPasswordChange(text) {
    this.props.passwordChanged(text);
}

onConfirmPasswordChange(text) {
    this.props.confirmPasswordChanged(text);
}

onLoginButtonPress() {
    let {email, password} = this.props;
    let currentAnonymousFirebaseUser = firebase.auth().currentUser;
    this.props.loginUser({email, password, currentAnonymousFirebaseUser});
}

renderError() {
    if (this.props.error) {
      return (
        <View
          style={{backgroundColor: "#fff", paddingBottom: 5, paddingTop: 5}}>
          <Text style={styles.errorTextStyle}>{this.props.error}</Text>
        </View>
      );
    }
}

renderLoginButton() {
    if (this.props.loading) {
        return <Spinner size="large" />;
    }
    return <Button onPress={() => this.onLoginButtonPress()}>Login</Button>;
}

render() {
    return (
      <Card>
        <CardSection>
          <Row>
            <Input
              label="Email"
              placeholder="email@gmail.com"
              onChangeText={this.onEmailChange.bind(this)}
              value={this.props.email}
            />
          </Row>
        </CardSection>

        <CardSection>
          <Row>
            <Input
              secureTextEntry
              label="Password"
              placeHolder="password"
              onChangeText={this.onPasswordChange.bind(this)}
              value={this.props.password}
            />
          </Row>
        </CardSection>

        {this.renderError()}

        <CardSection>
          <Row>{this.renderLoginButton()}</Row>
        </CardSection>
      </Card>
      );
   }
}

const mapStateToProps = ({auth}) => {
    const {email, password, confirmPassword, error, loading} = auth;
    return {email, password, confirmPassword, error, loading};
};

export default connect(mapStateToProps, {
    emailChanged,
    passwordChanged,
    confirmPasswordChanged,
    loginUser
})(LoginScreen);

Reducer

const INITIAL_STATE = {
    email: "",
    password: "",
    confirmPassword: "",
    user: null,
    error: "",
    loading: false
};

export default (state = INITIAL_STATE, action) => {
    console.log(action);

    switch (action.type) {
        case EMAIL_CHANGED:
          return {...state, email: action.payload};

        case PASSWORD_CHANGED:
          return {...state, password: action.payload};

        case CONFIRM_PASSWORD_CHANGED:
          return {...state, confirmPassword: action.payload};

        case CREATE_USER_ACCOUNT:
          return {...state, loading: true, error: ""};

        case CREATE_USER_ACCOUNT_SUCCESS:
          return {...state, ...INITIAL_STATE, user: action.payload};

        case CREATE_USER_ACCOUNT_FAIL:
          return {...state, error: action.payload, loading: false};

       case LOGIN_USER:
          return {...state, loading: true, error: ""};

        case LOGIN_USER_ANONYMOUSLY:
          return {...state};

        case LOGIN_USER_SUCCESS:
          return {...state, ...INITIAL_STATE, user: action.payload};

        case LOGIN_USER_FAIL:
          return {...state, error: action.payload, loading: false};

        default:
          return state;
    }
};

Any help would be greatly appreciated!

Rex Low
  • 2,069
  • 2
  • 18
  • 47
Andrew Irwin
  • 691
  • 12
  • 40

2 Answers2

3

You can make another action for clearing your data in redux, For example

const clearData = () => {
  return{
  type: "CLEAR"
 };
};

and in your reducer you can just use this clearData, For example

 case "CLEAR"
 return {...state, ...INITIAL_STATE}

or

 case "CLEAR"
 return {...state, email: INITIAL_STATE.email}

It depends on your use case. When everything is done.

Just call this actions on your componentWillUnmount in your login screen

for example

componentWillUnmount() {
 this.props.clearData();
}
Andrew Irwin
  • 691
  • 12
  • 40
Sarmad Shah
  • 3,725
  • 1
  • 20
  • 42
  • But the thing is ... in a stackNavigator when you navigate back ... component will not be unmounted ... it just loses focus .. so `clearData` will not be called – Hend El-Sahli Apr 09 '19 at 18:21
  • in stacknavigator, when you press back. the current component will get unmounted, That thing is for parent components, And to solve that problems, there is a solution. you can use willfocus method from react-navigation – Sarmad Shah Apr 09 '19 at 18:22
  • console.log anything inside your event to see yourself ... and check it out https://stackoverflow.com/questions/48018084/componentdidmount-function-is-not-called-after-navigation – Hend El-Sahli Apr 09 '19 at 18:25
  • which navigation lib you using? and if react navigation, which version? – Sarmad Shah Apr 09 '19 at 18:28
  • I think the component will unmount, do one thing..use a local state in your component, see if it persists when you visit the component again. – Sarmad Shah Apr 09 '19 at 18:29
  • If the component will unMount when you press the back btn in the stack header ... then `componentDidMount` event should be fired each time you navigate back to it ... a console.log in `componentDidMount` should tell everything :) – Hend El-Sahli Apr 09 '19 at 18:34
  • Please share your code on expo snack, i will try to solve it for you :) – Sarmad Shah Apr 09 '19 at 18:36
  • Hi @SarmadShah, Thank you very much for answer. When I do `const clearData = () => { type: "CLEAR" } ` nothing happens, and in my actions creator file, it says, unnecessary label "type" and "CLEAR" is not an expression or a statement. If I try to use a dispatch in the function it says dispatch is not a function – Andrew Irwin Apr 10 '19 at 09:55
  • @SarmadShah I fixed the problem I had in the above comment. All I had to do was add a return to the action creator `export const clearData = () => { return { type: CLEAR_DATA }; };` do you need to update your answer to include the return too, or are you able to do it without the return. Thanks very much Andrew – Andrew Irwin Apr 10 '19 at 10:19
  • 1
    happy to help, and do remember, stack navigator always unmounts the child view @hen – Sarmad Shah Apr 10 '19 at 10:39
1

Solution 1

Add a reset param to your LoginScreen when you navigate to it:

class LoginScreen extends React.Component {
  componentWillReceiveProps(nextProps) {
    const nextReset = nextProps.navigation.getParam("reset");
    const reset = this.props.navigation.getParam("reset");

    if (nextReset && nextReset !== reset) {
      // Create  a redux action to clear field values:
      nextProps.resetFieldsAction();
    }
  }
}

This's how you navigate to your LoginScreen:

this.props.navigation.navigate("LoginScreen", { reset: true });

Solution 2

import {NavigationEvents} from 'react-navigation';

Add this component to your render method and call your redux action when your component re-gain focus:

<NavigationEvents onDidFocus={() => this.props.resetFieldsAction()} />
Hend El-Sahli
  • 6,268
  • 2
  • 25
  • 42