Home > other >  Update snackbar state from parent component
Update snackbar state from parent component

Time:02-23

I am trying to dismiss the snack bar after the user presses ok or after the duration. I tried passing an extra variable to the component and changing state but it does not work. Here is my code for the LogIn page that uses the snackbar component that renders only after a bad login request , its not the whole code:

 const [error, setError] = React.useState(false);
  const [username, setUsername] = React.useState('');
  const [password, setPassword] = React.useState('');

  const [visible, setVisible] = React.useState(false);

  /* const form = createForm(data); */
  return (
    <View style={Style.container}>
      {error && (
        <View style={{width: '30%', height: '10%'}}>
          <Snack_alert
            message={'Wrong username or password!'}
            textcolor={'white'}
            btn_color={'white'}
            snack_color={'red'}
            dismiss={() => {
              setVisible(false);
            }}
          />
        </View>
      )}

and here is the child component:

export default function Snack_alert({

  message,
  textcolor,
  btn_color,
  snack_color,
  dismiss

}) {
  return (
    <Snackbar
      visible={true}
      onDismiss={() => {
        {
        dismiss
        }
      }}
      duration={2500}
      theme={{
        colors: {
          surface: textcolor,
          accent: btn_color,
          onSurface: snack_color,
        },
      }}
      //surface: text color , accent: undo color, onSurface: snackbar color
      action={{
        label: 'Ok',
        onPress: () => {
          {
           dismiss
          }
        },
      }}>
      {message}
    </Snackbar>
  );
}

Also later in my code I update the setError to true so that I can render the snackbar , I am unsure if that causes any problems. Thanks in advance!

CodePudding user response:

The way you pass the prop dismiss to the Snack_alert component from the parent container is correct. The prop dismiss holds a function. Thus,

onDismiss={() => {
    {
        dismiss
    }
}}

is basically the same as writing

function dismiss() {
    setVisible(false)
}

function onDismiss() {
  {
    dismiss
  }
}

Let us log what will happen if we call onDismiss(). This yields

undefined

since onDismissdoes not return anything. Let us return dismiss and see what will happen.

function onDismiss() {
  {
    return dismiss
  }
}

If we call onDismiss again it yields the following output.

function dismiss() {
    setVisible(false);
} 

The function dismiss is now correctly returned, but it is not called. This is fine if you know that the Snackbar component will internally do something like this.

const foo = onDismiss()
foo()

The constant foo gets assigned the return value of the function onDismiss which is the function dismiss that we have passed as a prop. We can call dismiss by calling foo. This will correctly set the visible state to false. Notice that it is more convenient to write

onDismiss={dismiss}

since then the prop onDismiss gets the prop dismiss assigned which is the function dismiss that we have passed earlier. Thus, instead of calling onDismiss as a function in order to retrieve dismiss, the Snackbar container can now directly call onDismiss() and this will call dismiss().

My last comment is how the Snackbar component works. It expects the following.

<Snackbar
  visible={visible}
  onDismiss={() => setVisible(false)}
  ...
/>

Thus, onDismiss is a function that when called sets the visible state of the component. Hence, you need to fix two things.

  1. Change the way you are passing the function dismiss.
  2. Pass the visible state to Snack_alert from the parent container.

By knowing this, we can construct a working version of your code as follows.

onst [error, setError] = React.useState(false);
  const [username, setUsername] = React.useState('');
  const [password, setPassword] = React.useState('');

  const [visible, setVisible] = React.useState(false);

  /* const form = createForm(data); */
  return (
    <View style={Style.container}>
      {error && (
        <View style={{width: '30%', height: '10%'}}>
          <Snack_alert
            message={'Wrong username or password!'}
            textcolor={'white'}
            btn_color={'white'}
            snack_color={'red'}
            visible={visible}
            dismiss={() => {
              setVisible(false);
            }}
          />
        </View>
      )}


...

export default function Snack_alert({

  message,
  textcolor,
  btn_color,
  snack_color,
  dismiss,
  visible

}) {
  return (
    <Snackbar
      visible={visible}
      onDismiss={dismiss}
      duration={2500}
      theme={{
        colors: {
          surface: textcolor,
          accent: btn_color,
          onSurface: snack_color,
        },
      }}
      //surface: text color , accent: undo color, onSurface: snackbar color
      action={{
        label: 'Ok',
        onPress: dismiss,
      }}>
      {message}
    </Snackbar>
  );
}

CodePudding user response:

action={{ label: 'Ok', onPress: () => { { dismiss } }, }}

You don't call the dismiss-function. Either add parenthesis:

onPress: () => {
  dismiss()
}

Or just pass the function directly:

onPress: dismiss
  • Related