0

I want to create a login page where an error message is displayed when fields are empty. I use function components, state and props to keep the UI separated from the logic. So I have a UserSignInController which returns a UserSignInView which gets displayed on screen.

When I set a onPress callback for the login button, it calls onClickCheckLogin() in the controller. But setting the error message only works if I use an arrow function as a prop, if I use .bind(this) it doesn't.

This works UserSignInController.js:

import React, {useState} from 'react';
import { Linking, Alert } from 'react-native';
import UserSignInView from './UserSignInView';
import User from '../../User';

const renderSignInView = () =>
{
  const [errorMessage, setErrorMessage] = useState('');
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  return (
      <UserSignInView
          errorMessage = {errorMessage}
          setUsername = {setUsername}
          setPassword = {setPassword}
          //arrow function passing the state to onClickCheckLogin
          checkLogin = {() => { onClickCheckLogin(username, password, setErrorMessage)}}
          openPrivacyPolicy = {onClickOpenPrivacyPolicy}
      />
  )
};

const onClickCheckLogin = (username, password, setMessageFunction) =>
{
    if(!! username && !! password)
    {
      console.log("yeee");
    }else 
    {
      console.log('doooo');
      setMessageFunction('Username/password empty');
    } 
};

This does not work UserSignInController.js:

import React, {useState} from 'react';
import { Linking, Alert } from 'react-native';
import UserSignInView from './UserSignInView';
import User from '../../User';

const renderSignInView = () =>
{
  const [errorMessage, setErrorMessage] = useState('');
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  //bind function instead of arrow function
  onClickCheckLoginCallback = onClickCheckLogin.bind(this);

  return (
      <UserSignInView
          errorMessage = {errorMessage}
          setUsername = {setUsername}
          setPassword = {setPassword}
          //use the binded version
          checkLogin = {onClickCheckLoginCallback}
          openPrivacyPolicy = {onClickOpenPrivacyPolicy}
      />
  )
};

const onClickCheckLogin = () =>
{
    if(!! this.username && !! this.password)
    {
      console.log("yeee");
    }else 
    {
      console.log('doooo');
      this.setErrorMessage('Username/password empty');
    } 
};

With this I get an error TypeError: _this.setErrorMessage is not a function. (In '_this.setErrorMessage('Username/password empty')', '_this.setErrorMessage' is undefined)

TruffelNL
  • 480
  • 5
  • 22

2 Answers2

0

I think that the problem is that renderSignInView is defined as an arrow function itself. The this keyword is not pointing to the component then, so calling setErrorMessage results in an error. Try changing to the following:

function renderSignInView(){
//Component
}
Andrea Roveroni
  • 184
  • 1
  • 6
  • Thanks for your answer. Unfortunately it didn't help. I also changed `onClickCheckLogin` to your suggestion but I still get the same error. – TruffelNL Sep 11 '21 at 08:57
  • Try logging the `this` property – Andrea Roveroni Sep 11 '21 at 08:58
  • Could you tell me how? I can only get `[Object]` `[object GlobalObject]` or `JSON.stringify cannot serialize cyclic structures` when I log it to the console using `.toString()` or something like that. – TruffelNL Sep 11 '21 at 09:17
0

I found the answer here. You can't access local properties of a function from the outside. That globalObject displayed with console.log is just the window object. So, binding with .bind() can't work. As an alternative, you may pass the setErrorMessage property as an argument, and also the username and password.

I wrote on a separate answer to better distinguish from the first one

Andrea Roveroni
  • 184
  • 1
  • 6
  • Then I'm confused as to what `bind(this)` does when used in functional components in React-Native. Since I thought that would bind the called function to the parent context (with properties, especially with `state` properties). I will use your suggestion as that was what I had and what worked. – TruffelNL Sep 12 '21 at 09:16