# How to make React component aware of theme switch?

**URL:** <https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944>\
**Category:** UXP Plugin API\
**Tags:** react, ui, uxp, javascript\
**Created:** [November 27, 2021, 8:39am UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944 "2021-11-27T08:39:28Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [November 27, 2021, 8:39am UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/1 "2021-11-27T08:39:28Z")

</div>

My problem is, that I can not detect correct theme on a dialog after it’s switched.

Steps to reproduce:

1. Add provided component to the panel - it will render a button
2. Click the button - it will show a dialog with active theme
3. Close dialog
4. Switch theme
5. Click button again - still shows old theme

I want it to show current theme

This is a very simplified version of what I have (kept it in a single file to not pollute the code)

```auto
// DialogThemeTest.tsx

import ReactDOM from "react-dom";
import photoshop from "photoshop";

const Theme = {
    DARKEST: "darkest",
    DARK: "dark",
    LIGHT: "light",
    LIGHTEST: "lightest",
}

const ThemeMap = new Map([
    ["kPanelBrightnessDarkGray", Theme.DARKEST],
    ["kPanelBrightnessMediumGray", Theme.DARK],
    ["kPanelBrightnessLightGray", Theme.LIGHT],
    ["kPanelBrightnessOriginal", Theme.LIGHTEST],
])

const getTheme = () => {
    const result = photoshop.action.batchPlay(
        [
            {
                "_obj": "get",
                "_target": [
                    {"_property": "kuiBrightnessLevel"},
                    {"_ref": "application", "_enum": "ordinal", "_value": "targetEnum"}
                ],
                "_options": {"dialogOptions": "dontDisplay"}
            }
        ],
        {"synchronousExecution": true});

    const pinned = result[0].kuiBrightnessLevel._value;

    return ThemeMap.get(pinned) ?? Theme.DARK
}

const DialogContent = ({dialog}) =>
    <>
        <sp-body>{getTheme()}</sp-body>
        <sp-footer>
            <sp-button onClick={() => dialog.close()}>Close</sp-button>
        </sp-footer>
    </>

const dialogController = (Component) => {
    let dialogElement

    return async () => {
        if (!dialogElement) {
            dialogElement = document.createElement("dialog");
            ReactDOM.render(Component({dialog: dialogElement}), dialogElement);
        }

        document.body.appendChild(dialogElement);
        await dialogElement.uxpShowModal({title: "dialogThemeTest"});
        dialogElement.remove();
    }
}

const dialogOpener = () => dialogController(DialogContent)

export default () =>
    <sp-button onClick={dialogOpener()}>
        Check theme
    </sp-button>

```

I was thinking about unmounting the dialog, but it gives me error it was rendered with different version of React 😕

---

<div class="post-metadata">

**Author:** ![simonhenke](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/simonhenke/32/957_2.png) [@simonhenke](https://forums.creativeclouddeveloper.com/u/simonhenke)\
**Post date:** [November 27, 2021, 12:25pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/2 "2021-11-27T12:25:47Z")

</div>

Could you maybe post a screenshot or video demonstrating the behavior? I think I didn’t quite understand the full use case yet.

---

<div class="post-metadata">

**Author:** ![simonhenke](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/simonhenke/32/957_2.png) [@simonhenke](https://forums.creativeclouddeveloper.com/u/simonhenke)\
**Post date:** [November 27, 2021, 12:32pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/3 "2021-11-27T12:32:32Z")

</div>

> [@Karmalakas](#):
>
> `<sp-body>{getTheme()}</sp-body>`

Also, you could try to put a `console.log` into the `getTheme` function. My first suspicion is that this gets only called once at the start.

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [November 27, 2021, 12:49pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/4 "2021-11-27T12:49:49Z")

</div>

> [@simonhenke](#):
>
> My first suspicion is that this gets only called once at the start.

And you’re right. It is called only once. I believe it’s because `DialogContent` is already in a variable and you can pass it to dialog controller what you want - it already has the result of `getTheme()`. So that’s the part I can’t figure out how to force re-render or reinitiate that content.

I also believe it should work with proper unmount by calling `ReactDOM.unmountComponentAtNode(dialogElement)` right before `dialogElement.remove()`, but then I get this error “[_The node you’re attempting to unmount was rendered by another copy of React_](https://issueexplorer.com/issue/facebook/react/22343)” (scroll down to the very last comment)

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [November 27, 2021, 1:03pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/5 "2021-11-27T13:03:42Z")

</div>

Here’s the video

---

<div class="post-metadata">

**Author:** ![simonhenke](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/simonhenke/32/957_2.png) [@simonhenke](https://forums.creativeclouddeveloper.com/u/simonhenke)\
**Post date:** [November 27, 2021, 1:55pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/6 "2021-11-27T13:55:51Z")

</div>

Unmounting `dialogElement` will not solve the issue, which is that the `DialogContent` component does not re-render. There are multiple ways to do that, one of that is updating its props. Interestingly, even if you create a new `dialog` element every time, this doesn’t trigger a re-render as React thinks it’s the same object. Passing the current theme however works fine:

```auto
const DialogContent = ({dialog, theme}) => {
  return <>
        <sp-body>{theme}</sp-body>
        <sp-footer>
            <sp-button onClick={() => dialog.close()}>Close</sp-button>
        </sp-footer>
    </>
}

const dialogController = (Component) => {
    let dialogElement
    return async () => {
        dialogElement = document.createElement("dialog");
        ReactDOM.render(Component({dialog: dialogElement, theme: getTheme()}), dialogElement);
        document.body.appendChild(dialogElement);
        await dialogElement.uxpShowModal({title: "dialogThemeTest"});
        dialogElement.remove();
    }
}

```

If you rather want to encapsulate the theme fetching logic in the `DialogContent` as you did before, I’d probably make use of the `key` property that React uses to reference component instances.

```auto
const DialogContent = ({dialog}) => {
  return <>
        <sp-body>{getTheme()}</sp-body>
        <sp-footer>
            <sp-button onClick={() => dialog.close()}>Close</sp-button>
        </sp-footer>
    </>
}

const dialogController = (Component) => {
    let dialogElement
    return async () => {
        dialogElement = document.createElement("dialog");
        ReactDOM.render(Component({dialog: dialogElement, key: Math.random()}), dialogElement);
        document.body.appendChild(dialogElement);
        await dialogElement.uxpShowModal({title: "dialogThemeTest"});
        dialogElement.remove();
    }
}

```

Instead of Math.random, you could also assign a unique UUID for the dialog every time. There’s probably a more elegant solution to solve all this, but this was the first thing that came to my mind.

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [November 27, 2021, 3:06pm UTC](https://forums.creativeclouddeveloper.com/t/how-to-make-react-component-aware-of-theme-switch/3944/7 "2021-11-27T15:06:37Z")

</div>

Thans once again 🙂 I’ll stick with the `key` solution at least until I become aware of a better one, because I think it’s more correct - when I close the dialog, I want it to re-rendered next time I open it. This actually might also help solving another very similar issue I’m having (will check that later)

This is the bit I changed to (always creating new `dialogElement` and `uuid()` on dialog open)

```auto
return async () => {
        const dialogElement = document.createElement("dialog")
        ReactDOM.render(Component({key: uuid(), dialog: dialogElement}), dialogElement)

        document.body.appendChild(dialogElement);

        await dialogElement.uxpShowModal(dialogOpts)
        dialogElement.remove()
    }

```
