DEV Community

Discussion on: React vs Signals: 10 Years Later

 
dan_abramov profile image
Dan Abramov

Hooks weren't what I was expecting.

Yeah that’s pretty interesting. I haven’t thought about it from this perspective. To me Hooks are very functional in the classical sense. They’re a universe apart from Knockout style, so I was surprised by your mention of trading away the pure model. Hooks do not trade it away, they’re the clearest representation of that model. But I can see now how superficially they might look like some Knockout-style code. That might explain why people sometimes really struggle with them. Guess that’s similar to Solid code looking deceptively Reacty — when it’s really not. That’s a useful insight.

Thread Thread
 
trusktr profile image
Joe Pea • Edited

The examples above are very very simple. They are complete beginner examples, and don't really show where things get either a lot more complex, or way simpler. When you really use both React and Solid, then you'll see which is simpler as app requirements grow.

Here's just one simple example with pure Solid that I challenge anyone to write in pure React without importing additional libraries and with the same simplicity:

import {createSignal, createEffect} from `solid-js`

const [n, setN] = createSignal(0)

setInterval(() => setN(n() + 1), 500)

function One() {
  return <div>value in One: {n()}</div>
}

function Two() {
  return <div>value in Two: {n() * 2}</div>
}

// DOM!
document.body.append(<One />)
document.body.append(<Two />)
Enter fullscreen mode Exit fullscreen mode

Solid playground example

Example on CodePen with no build tools:

Thread Thread
 
karl_okeeffe profile image
Karl O'Keeffe

This was an interesting challenge, as I could see lots of ways of building this in React depending on which parts of the above code were considered critical.

The most natural way I would write it is:

const One = ({count}) => {
  return <div>value in One: {count}</div>
}

const Two = ({count}) => {
  return <div>value in Two: {count * 2}</div>
}

const App = () => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setInterval(() => {
      setCount(count => count + 1);
    }, 500)
  }, []);

  return(
    <>
      <One count={count} />
      <Two count={count} />
    </>
  );
}

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

codepen.io/karlokeeffe/pen/vYzxPEX

The big difference with the above Solid code is that this moves the state handling into a top level React component so that React will re-render our components when the state changes.

We also need to wrap the setInterval call in a useEffect in order to kick off the interval from a React component.

Thread Thread
 
tomsherman profile image
Tom Sherman • Edited

You don't technically even need the top level App component or the state...

const One = ({count}) => {
  return <div>value in One: {count}</div>
}

const Two = ({count}) => {
  return <div>value in Two: {count * 2}</div>
}

const root = React.createRoot(document.getElementById("app"));
let count = 0;

setInterval(() => {
  count++;
  root.render(
    <>
      <One count={count} />
      <Two count={count} />
    </>,
  );
}, 500);
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
akmjenkins profile image
Adam

This thread is crazy.

Impure solidjs components being rebuilt using pure react components.

Let's turn this into a different challenge: write the code and the tests for each of these in solid and react

Thread Thread
 
ninjin profile image
Jin • Edited
const [n, setN] = createSignal(0)
setInterval(() => setN(n() + 1), 500)
Enter fullscreen mode Exit fullscreen mode

This code looks very simple and concise. But this is incorrect code, since the timer running will never stop. It's a time bomb. If you write this code correctly with the timer reset when removing the component, then the code will turn out to be not so concise at all. And I am silent about the fact that this code ticks not 2 times per second, but at unpredictable intervals of time, which introduces a progressive systematic error. To avoid this, you need to measure the time that has elapsed since the timer started.

In $moll there is a special store ticking with a given accuracy for this. Example:

const start = Date.now()

const { elapsed, run } = $mol_wire_let({
    elapsed: ()=> $mol_state_time.now( 1e3 ) - start,
    run: ()=> console.log( 'Elapsed: ', elapsed() / 1e3 ),
})

run()
setTimeout( ()=> run.atom.destructor(), 1e4 )
Enter fullscreen mode Exit fullscreen mode