skip to Main Content

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?

2

Answers


  1. If you want to continue using @preact/signals-react within a React application and have the UI react to changes in the signal, you need to integrate it in such a way that changes in signal values trigger React component re-renders. One approach could be to use a custom hook that ties signal changes to a state update, something like this:

    import { useEffect, useState } from 'react';
    
    function useSignal(signal) {
        const [value, setValue] = useState(signal.value);
    
        useEffect(() => {
            const effect = signal.effect(() => {
                setValue(signal.value);
            });
    
            return () => effect.dispose();
        }, [signal]);
    
        return value;
    }
    
    // In your component
    function App() {
        const dialogOpen = useSignal(addItemDialog);
        // ...
    }
    
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search