Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

signals/react: React components rendered as child routes with React Router don't update when using signal.value #273

Open
cafreeman opened this issue Nov 10, 2022 · 8 comments
Labels

Comments

@cafreeman
Copy link

Hi there,

I've recently been experimenting with using Signals in React and have discovered a strange behavior when using it in concert with React Router. It seems that when you render a component in a React Router <Outlet> (as a child route), there's something about the interaction between the Outlet and signals that causes the component itself to not actually update.

However, this can be fixed by only referring the signal itself (e.g. <div>{signal}</div> as opposed to <div>{signal.value}</div>. If you do that, the component suddenly behaves as expected.

I've created a repo with a small reproduction here: https://github.com/cafreeman/signals-react-weirdness

Please let me know if there's any other information I can provide.

Thanks!

@cafreeman
Copy link
Author

cafreeman commented Nov 14, 2022

Update: this appears to only happen when using the automatic JSX runtime. If I instead use the classic runtime, the component behaves as expected.

This might also be related to #269

@jesseagleboy
Copy link

I'm happy to see someone else posted about this. I'm using signals within React Router and either the HMR will crash my page or within a sandbox demo I did, just importing signals into a file will give an error. I've tested importing signals in React non-React-Router projects and they work just fine. I have no clue what Signals does to the React component that alters how React Router handles the routing.

image

Live Testing

@cedeber
Copy link

cedeber commented Nov 22, 2022

Switching to the JSX "classic" mode didn't help for me.

@theverything
Copy link

react-router throws an error if @preact/signals-react is imported to the same project. This is because the preact lib wraps components in a Proxy. When react-router calls this code https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/components.tsx#L572 it errors because the Router type doesn't match the Proxy type.

@harshithr
Copy link

hello, even i am facing same issue as above, -- Uncaught Error: [Route] is not a component --

So is there any workaround to resolve this issue?

@DmnChzl
Copy link

DmnChzl commented May 24, 2023

Hi 👋
I had this same issue with version 1.2.X of @preact/signals-react:

Uncaught Error: [Route] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
    at invariant (history.ts:480:11)
    at components.tsx:593:5
    at react.development.js:1195:17
    at react.development.js:1158:17
    at mapIntoArray (react.development.js:1049:23)
    at mapIntoArray (react.development.js:1099:23)
    at mapChildren (react.development.js:1157:3)
    at Object.forEachChildren [as forEach] (react.development.js:1194:3)
    at createRoutesFromChildren (components.tsx:575:18)
    at Routes (components.tsx:413:20)

But, it seems fixed in version 1.3.X. No more problem using signals, computed or even effect despite the use of a routing ([email protected]). My code:

import { computed, effect, signal } from "@preact/signals-react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Link, Navigate, Route, Routes } from "react-router-dom";

const counter = signal(0);
const isEven = computed(() => counter.value % 2 === 0);

effect(() => {
  console.log(isEven.value ? "Even" : "Odd");
});

const increment = () => (counter.value += 1);
const decrement = () => (counter.value -= 1);

function Result() {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <span>Value: {counter.value}</span>
      <Link to="/btn-grp">Go To ButtonGroup</Link>
    </div>
  );
}

function ButtonGroup() {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", flexDirection: "row" }}>
        <button onClick={decrement}>-1</button>
        <button onClick={() => (counter.value = 0)}>Reset</button>
        <button onClick={increment}>+1</button>
      </div>
      <Link to="/result">Go To Result</Link>
    </div>
  );
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Navigate to="/result" />} />
      <Route path="/result" element={<Result />} />
      <Route path="/btn-grp" element={<ButtonGroup />} />
    </Routes>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

Can anyone else confirm?

@aspizu
Copy link

aspizu commented Apr 3, 2024

This might be related to the issue I am having, I too am using React router. If i use a mySignal.value created using the signal() function, exported from a module directly inside my component then my component will re-render on signal updates. But, if i call a function which eventually uses mySignal.value, it won't update on changes. It only works if the signal value was directly used.

@XantreDev
Copy link
Contributor

@JoviDeCroock Probably it's not actual too, probably it's related with fact only some of high order component have been patched in previous implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants