Search code examples
reactjsmaterial-uipreactpreact-signal

Why is my React Signals dialog not opening here?


I am trying to control a MUI dialog with a signal, but even with the < p > the value from the signal is not rendered. However, the value of the signal is changed in the console. So if i click the FAB nothing happens.

App.jsx

import Fab from "@mui/material/Fab";
import AddIcon from "@mui/icons-material/Add";
import "./App.css";

import AddItemDialog from "./AddItemDialog";
import { signal } from "@preact/signals-react";

const addItemDialog = signal(false);

function App() {
    console.log("Render App");

    const fabStyle = {
        position: "absolute",
        bottom: 16,
        right: 16,
    };

    function openDialog() {
        addItemDialog.value = true;
    }

    return (
        <>
            <p>{addItemDialog.value}Test</p>
            <AddItemDialog addItemDialog={addItemDialog} />
            <Fab sx={fabStyle} color="primary" onClick={openDialog}>
                <AddIcon />
            </Fab>
        </>
    );
}

export default App;

AddItemDialog.jsx

mport React, { useRef } from "react";
import { Dialog, DialogTitle, DialogContent } from "@mui/material";

export default function AddItemDialog({ addItemDialog }) {
    console.log("Render Dialog");

    const name = useRef();

    function close() {
        addItemDialog.value = false;
    }

    return (
        <Dialog open={addItemDialog.value} onClose={close} fullWidth maxWidth="sm">
            <DialogTitle>Add Item</DialogTitle>
            <DialogContent>
                <input type="text" ref={name} />
            </DialogContent>
        </Dialog>
    );
}

Preview of Website

Replacing the signal to useState would work, but the whole app rerenders after changing

Edit: I got it to work by putting both compenents into another one and using the state there, but still why doesn't it work with the signal?


Solution

  • This doesn't work as you haven't fully followed the getting started instructions: https://github.com/preactjs/signals/tree/main/packages/react#react-integration

    As of v2, you need to use the Babel plugin or the useSignals() hook.

    import { signal } from "@preact/signals-react";
    import { useSignals } from "@preact/signals-react/runtime";
    
    const addItemDialog = signal(false);
    
    function App() {
        useSignals();
        //...
    }
    

    Please ignore that other user, they are entirely misinformed. Signals do trigger React component re-renders, without this, they'd be rather useless.

    Edit: The video you linked to was using Signals v1, which had some edge cases and the ire of the React core team, so we changed it. It's not as succinct, but we deemed this to be a better option than to make signals exclusive to Preact users