react-native-paper icon indicating copy to clipboard operation
react-native-paper copied to clipboard

New arch disabled button theme color

Open iM-GeeKy opened this issue 1 year ago • 3 comments

Current behaviour

When using "react-native": "~0.75.3", the disabled button color theme is different than when using "react-native": "0.74.5",. The same behavior is exhibited on Android.

Expected behaviour

Theming with the latest version of react-native should behave consistently with all previous versions.

How to reproduce?

  1. yarn install.
  2. yarn run ios.

https://github.com/iM-GeeKy/paper-button-disabled-bug

Preview

"react-native": "~0.75.3", https://github.com/user-attachments/assets/d2d3ac54-34ca-47d8-a9ae-fe637b9e7687

"react-native": "0.74.5", https://github.com/user-attachments/assets/6cb50a45-a41f-4704-b7bc-7e41b8c93460

What have you tried so far?

Simply changing between the different versions yields different theming behavior for the disabled prop on a Button.

Relates to new arch support

Your Environment

software version
ios 18.0
android 14.0
react-native 0.75.3
react-native-paper 5.12.5
node 20.17.0
npm or yarn yarn
expo sdk 51.0.36

iM-GeeKy avatar Oct 07 '24 13:10 iM-GeeKy

Good evening, I'm a beginner in the React Native environment (coming from ReactJS), and I would like to understand if this problem you're reporting is that the Button's backgroundColor doesn't change as the "disabled" property changes?

I use exactly the same packages, but NodeJS 20 and when a button is enabled or disabled, only the textColor changes, but not the backgroundColor

I need to directly change the useState of disabled to "true" or "false" so that it renders the correct backgroundColor color when the screen is rendered for the first time

But if I click on the button to change the disabled, the background color doesn't change

Is this exactly your problem?

My code: `import React, { useState } from 'react';

import { Switch, StyleSheet, View } from 'react-native';

import { Button } from 'react-native-paper';

export default function SimpleForm() { const [isEnabled, setIsEnabled] = useState(false);

const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, button: { backgroundColor: isEnabled ? '#9ACBFF' : '#E2E2E5', } });

return ( <View style={styles.container}> <Switch value={isEnabled} onValueChange={() => setIsEnabled(!isEnabled)} /> <Button icon="login" disabled={!isEnabled} styles={styles.button} mode='contained' > SUBMIT </Button> </View> ); }`

chartliex avatar Oct 17 '24 21:10 chartliex

@ch4rliedev The background color is inconsistent. In all previous versions below "react-native": "0.74.5" the background in this scenario is purple and when disabled is grey. However, in "react-native": "~0.75.3", with the new arch enabled, the same theme yields a grey background when enabled and disabled only the button text color changes.

iM-GeeKy avatar Oct 17 '24 22:10 iM-GeeKy

I understand now, this error only occurs on Android/ios because I tested it on Chrome (react-native-web) and the change between enabled and disabled was successful

chartliex avatar Oct 18 '24 00:10 chartliex

I need to directly change the useState of disabled to "true" or "false" so that it renders the correct backgroundColor color when the screen is rendered for the first time

But if I click on the button to change the disabled, the background color doesn't change

I have same issue on react native 0.7.6

zkteco-home avatar Oct 28 '24 06:10 zkteco-home

I just noticed this too after upgrading to the new architecture. If anyone is after a temporary workaround, you can force the button to render as a new component instance (unmount and remount) by setting a key based on whether it's disabled or not, e.g.:

<Button
  disabled={disabled}
  key={disabled ? "disabled" : "enabled"}
/>

Edit: Please be aware that it's not only the disabled prop that is affected by this issue - other props affecting appearance may be impacted too.

bradchristensen avatar Oct 28 '24 21:10 bradchristensen

Thanks @bradchristensen! However wouldn't that workaround cause issues if there are more than one button? Would it be safer to always rerender buttons with something like this?

<Button
  disabled={disabled}
  key={Math.random()}
/>

simonbengtsson avatar Oct 28 '24 21:10 simonbengtsson

I wouldn't personally use Math.random() since it would cause the button to re-mount on every render, which isn't strictly necessary, although to be fair you'd probably never notice unless it was being rendered in some sort of performance-critical context.

But you're right - my understanding of when this would be an issue would be if you had two buttons that were siblings within the same view or fragment (i.e. side-by-side) but please correct me if I'm wrong! You'd just need to be careful to ensure that the keys didn't overlap in that case - you could do that by giving each one its own unique prefix like cancel_disabled and confirm_disabled.

bradchristensen avatar Oct 28 '24 21:10 bradchristensen

Yeah certainly not ideal to rerender each button on each update. My understanding after skimming the docs is that keys should be globally unique however so it would not be enough to only set siblings to have different keys. Could very much be wrong on that however.

simonbengtsson avatar Oct 28 '24 22:10 simonbengtsson

I just noticed this too after upgrading to the new architecture. If anyone is after a temporary workaround, you can force the button to render as a new component instance (unmount and remount) by setting a key based on whether it's disabled or not, e.g.:

<Button disabled={disabled} key={disabled ? "disabled" : "enabled"} />

This worked for me, thanks!

If you have multiple buttons (or any component) adjacent to each other in React Native, you should be setting a unique key on each anyway, so this could be modified to:

<Button
  key={`button1_${disabled}`}
  disabled={disabled}
/>

This will ensure that changing disabled will correctly re-render the button, and also won't needlessly re-render if it doesn't change.

craiganderson-iotv avatar Oct 29 '24 00:10 craiganderson-iotv

Just for avoidance of doubt, here's a snippet from the React docs on using keys (https://react.dev/learn/rendering-lists):

Keys must be unique among siblings. However, it’s okay to use the same keys for JSX nodes in different arrays.

The docs refer to arrays because that's the only place where you always need to explicitly assign keys, but the same principle applies here 🙂

bradchristensen avatar Oct 29 '24 01:10 bradchristensen

I also encountered a similar issue when switching to dark mode, the button does not render the correct background color

  • react native: 0.75.4
  • paper: 5.12.5

linhh-phv avatar Nov 01 '24 18:11 linhh-phv

Also have the same issue

  • react-native: 0.76.1
  • react-native-paper: 5.12.5

I have been trying to find the core of the issue and it seems it has something to do with the Animated.Value.interpolate function used for the shadows and the backgroundColor in the Surface component, when disabling the shadows, the color of the button changes correctly.

DGVIP avatar Nov 05 '24 16:11 DGVIP

My workaround to this issue is to make a new button component as a wrapper for react native paper that takes the enabled and disabled value + the button text (children) as it's key. this can then be used everywhere. (Assuming you don't have multiple button with the same text, which is very unlikely

import React, { ComponentProps } from 'react';
import { Button as RNPButton } from 'react-native-paper';

export default function Button(props: ComponentProps<typeof RNPButton>) {
  return (
    <RNPButton
      {...props}
      key={(props.disabled ? 'disabled' : 'enabled') + props.children}
    />
  );
}

Noahkoole avatar Nov 07 '24 16:11 Noahkoole

My workaround to this issue is to make a new button component as a wrapper for react native paper that takes the enabled and disabled value + the button text (children) as it's key. this can then be used everywhere. (Assuming you don't have multiple button with the same text, which is very unlikely

import React, { ComponentProps } from 'react'; import { Button as RNPButton } from 'react-native-paper';

export default function Button(props: ComponentProps<typeof RNPButton>) { return ( <RNPButton {...props} key={(props.disabled ? 'disabled' : 'enabled') + props.children} /> ); }

I upgraded my project recently and is there any other way as I don't want to change it everywhere.

maiznadeem avatar Nov 18 '24 10:11 maiznadeem

I upgraded my project recently and is there any other way as I don't want to change it everywhere.

Same here. I expect (or hope) this to be resolved in a timely manner. Being able to render a disabled button in the correct color seems like pretty common use case and expected functionality for most.

My project is fine to revert the updates for now until this is fixed.

adam-kuhn avatar Nov 18 '24 17:11 adam-kuhn

This is working now, make sure the Expo Go & Expo Router is the latest version.

raajnadar avatar Jan 02 '25 09:01 raajnadar

This is working now, make sure the Expo Go & Expo Router is the latest version.

paper was update?

chartliex avatar Jan 02 '25 16:01 chartliex

The bug was not in paper, try clean the RN cache and try it will work

raajnadar avatar Jan 03 '25 13:01 raajnadar

Changing button's styling dynamically was broken in the previous version. It's fixed in 5.13.0, so closing the issue.

BogiKay avatar Jan 11 '25 19:01 BogiKay