callstack / react-native-paper

Material Design for React Native (Android & iOS)
https://reactnativepaper.com
MIT License
12.99k stars 2.1k forks source link

New arch disabled button theme color #4520

Open iM-GeeKy opened 1 month ago

iM-GeeKy commented 1 month ago

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
ch4rliedev commented 1 month ago

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 ( <Switch value={isEnabled} onValueChange={() => setIsEnabled(!isEnabled)} /> ); }`

iM-GeeKy commented 1 month ago

@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.

ch4rliedev commented 1 month ago

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

zkteco-home commented 3 weeks ago

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

bradchristensen commented 3 weeks ago

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.

simonbengtsson commented 3 weeks ago

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()}
/>
bradchristensen commented 3 weeks ago

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.

simonbengtsson commented 3 weeks ago

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.

craiganderson-iotv commented 3 weeks ago

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.

bradchristensen commented 3 weeks ago

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 🙂

linhh-phv commented 3 weeks ago

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

DGVIP commented 2 weeks ago

Also have the same issue

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.

Noahkoole commented 2 weeks ago

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}
    />
  );
}
maiznadeem commented 4 days ago

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) { 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.

adam-kuhn commented 4 days ago

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.