Skip to content

Switch component doesn't update visually on first press when used inside Portal/Modal #4789

Closed

Description

@enriquemomice

Current behaviour

When using React Native Paper's Switch component inside a Portal/Modal, the switch doesn't update its visual state on the first press, even though the state change is properly triggered and logged. The switch only updates visually on the second press. This issue doesn't occur when the same Switch is used outside of Portal/Modal contexts.

Expected behaviour

It should re render the switch as the state has changed.

How to reproduce?

// Minimal reproduction case
import { useState } from 'react';
import { Modal, Portal, Switch } from 'react-native-paper';

export default function BugDemo() {
  const [visible, setVisible] = useState(true);
  const [checked, setChecked] = useState(false);

  return (
    <Portal>
      <Modal visible={visible}>
        <Switch 
          value={checked} 
          onValueChange={setChecked} // State updates but UI doesn't on first press
        />
      </Modal>
    </Portal>
  );
}

What have you tried so far?

it works If I apply a dynamic key to the Switch like this

<Switch 
  key={`switch-${checked}`} // This fixes the issue
  value={checked} 
  onValueChange={setChecked}
/>

Your Environment

software version
ios 18.5
react-native 0.79.5
react-native-paper 5.14.5
node 22.17.1
expo sdk 53.0.20

Activity

  1. markovapps commented on Aug 10, 2025

    @markovapps

    I’m experiencing the same problem.
    It started after upgrading to:

    "react": "19.0.0"
    "expo": "^53.0.20"
    

    Previously I was on:

    "react": "18.3.0"
    "expo": "^52.0.47"
    

    The issue happens when Switch is inside Portal — it only updates visually on the second tap.
    If I move Portal outside of the component, the issue disappears.

    import { useState } from 'react';
    import { Modal, Portal, Switch } from 'react-native-paper';
    
    export default function BugDemoWrapper() {
      const [visible, setVisible] = useState(true);
    
      return (
        <Portal>
          <BugDemo visible={visible} />
        </Portal>
      );
    }
    
    function BugDemo({ visible }) {
      const [checked, setChecked] = useState(false);
    
      return (
        <Modal visible={visible}>
          <Switch 
            value={checked} 
            onValueChange={setChecked} // Works fine now
          />
        </Modal>
      );
    }
    
    
  2. einjunge99 commented on Oct 15, 2025

    @einjunge99

    I'm having the same issue even with native Switch component. Adding dynamic key fixed it, but seems to be odd.

  3. nicholascloud commented on Jan 12, 2026

    @nicholascloud

    Solved the problem by wrapping the mutator in a setTimeout(). YMMV.

    const { isSelected, onSelected } = props;
    const onToggle = useCallback(() => {
      setTimeout(() => onSelected(!isSelected), 50);
    }, [isSelected, onSelected])
    
    <Switch value={isSelected} onValueChanged={onToggle} />
    
  4. adrcotfas commented on May 28, 2026

    @adrcotfas
    Collaborator

    I wasn't able to reproduce this after #4957. It's not yet released but you can find it on main. Please reopen if the issue persists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions