React大好き侍が、「もうSolidJSでいいじゃん...//」ってなったワケ。

# Reactが好きです。
Reactが好きです。コンポーネントを関数として扱うのが好きです。
[SolidJS](https://github.com/solidjs/solid)はReactそっくりの書き心地(DX)を保ちつつ、Reactに足りない要素を兼ね備えた期待の新人です。

## コードの比較
### React
```jsx
const Counter = () => {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log(`Count: ${count}`)
  }, [count])

  return (
    <div>
      <div>{count}</div>
      <button onClick={() => setCount(prev => prev + 1)}>Add</button>
    </div>
  )
}
```
### SolidJS
```jsx
const Counter = () => {
  const [count, setCount] = createSignal(0)

  createEffect(() => {
    console.log(`Count: ${count()}`)
  }) //第２引数はありません。SolidJSが勝手に依存している状態を感知してくれます。

  return (
    <div>
      <div>{count()}</div>
      <button onClick={() => setCount(prev => prev + 1)}>Add</button>
    </div>
  )
}
```

そっくりですね。Reactを書いたことがある方なら容易に読めるはずです。

## SolidJS最大のメリット
パフォーマンスです。もうばちくそ速いです。下のグラフによるとReactより約2倍も速いです。[^1]なんならほぼVannilaJSと同じくらい速いです。
![パフォーマンス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656202/8d80cbfe-d24f-33f9-2888-0cfc239b13b6.png)

## なにが違うのか
記述はそっくりなのになぜこんなにもパフォーマンスに差が出るのか。それは単純に、SolidJSとReactは根本的に別物だからです。具体的な違いを幾つかあげます。

### 仮想DOMがない
Reactといえば仮想DOMみたいなとこあるのでもう完全に別物ですね。SolidJSはjsxを本物のDOMにコンパイルしています。
状態の更新の副作用としてDOMを書き換えているらしいです。[^2]

### コンポーネント(関数)が一度しか呼ばれない
Reactのコンポーネント内に直で`console.log`を書くと、状態が更新されるたびに実行されます。SolidJSのコンポーネント内に同じく`console.log`を書いても、最初に関数が呼ばれる時しか実行されません。
これはなかなか大きな違いです。Reactデベロッパーは日々、「不必要な再レンダリングを防ぐ」という課題に頭を悩ませていますが、SolidJSにおいてはそもそも「再レンダリング」は発生しないのです。


## SolidJSだから、できたこと。
こういった根本的な違いにより、SolidJSにのみ可能な芸当が存在します。

### `createSignal`でやりたい放題
`createSignal`は、`useState`とは違いHookではありません。React内に存在するHookのルールは適応されないのです。
コンポーネントの外に書くこともできますし、普通の関数内に書いたり、状況に応じて増やしたりもできます。

```jsx
//コンポーネントの外に書いても普通に動作します。
const [count, setCount] = createSignal(0)

const Counter = () => {
  return (
    <div>
      <div>{count()}</div>
      <button onClick={() => setCount(prev => prev + 1)}>Add</button>
    </div>
  )
}
```

```jsx
const Counter = () => {
 //コンポーネント内の関数でも呼べます。この例だと、コンポーネント内に直接customHookを書いているような感じです。
  const createCounter = () => {
    const [count, setCount] = createSignal(0)
    return { count, setCount }
  }

  const counterOne = createCounter()
  const counterTwo = createCounter()

  return (
    <div>
      <div>{counterOne.count()}</div>
      <button onClick={() => counterOne.setCount(prev => prev + 1)}>Add</button>

      <div>{counterTwo.count()}</div>
      <button onClick={() => counterTwo.setCount(prev => prev + 1)}>Add</button>
    </div>
  )
}
```

```jsx
const Counter = () => {
  const [counters, setCounters] = createSignal([])

  //ボタンがクリックされるたびにカウンターが増えます。
  const addCounter = () => {
    const [count, setCount] = createSignal(0)
    setCounters(prev => [...prev, { count, setCount }])
  }


  return (
    <div>
      <For each={counters()}>
        {counter => (
          <div>
            <div>{counter.count()}</div>
            <button onClick={() => counter.setCount(prev => prev + 1)}>
              Add
            </button>
          </div>
        )}
      </For>
      <button onClick={addCounter}>Add Counter</button>
    </div>
  )
}
```

#### ~~context~~状態管理ライブラリもいらない
察しのいい方はお気づきでしょうが、`createSignal`がどこにでも書けるなら上記の２つは必要ありません。`signals.ts`のようなファイルに、グローバルな状態を保管すればよいのです。
```ts
import { createSignal } from 'solid-js'

export const [count, setCount] = createSignal(0)
```

```jsx
import { count, setCount } from '../signals'

const Counter = () => {
  return (
    <div>
      <div>
        <div>{count()}</div>
        <button onClick={() => setCount(prev => prev + 1)}>Add</button>
      </div>
    </div>
  )
}
```
拍子抜けな程にシンプルに、グローバルな状態の管理ができますね。こういうのでいいんだよ。

6/10更新:
`createMemo`などの計算を含むグローバルな状態に関しては、`createContext`や`createRoot`を使用します。（詳しくは[こちら](https://www.solidjs.com/tutorial/stores_nocontext))
`createSignal`は、Contextなどではオーバーキルになるようなシンプルな状態を管理するのに適しています。
なお、ssrを使用する場は`createContext`を使用します。

### 直で`setInterval`
Reactの場合、こんな書き方をしたら再レンダーされるたびに新しく`setInterval`が登録されるので大変なことになります。一方SolidJSでは関数が一度しか呼ばれないので、トップレベルに`setInterval`を書いても問題ありません。
```jsx
const Counter = () => {
  const [count, setCount] = createSignal(0)

  const id = setInterval(() => {
    setCount(prev => prev + 1)
  }, 1000)

  onCleanup(() => {
    clearInterval(id)
  })

  return (
    <div>
      <div>{count()}</div>
      <button onClick={() => setCount(prev => prev + 1)}>Add</button>
    </div>
  )
}
```

## もうSolidJSでよくない？
まだReactが勝る部分はあるんですよ。Next.jsの存在とか、大きなコミュニティとか。
とはいっても、SolidJS版Next.jsは開発中とのことですし、コミュニティに関してもこれから育てていけばいいわけで。実際に海外では少しづつ注目を浴び始めていますしね[^3]。
かくいう自分も、日本におけるSolidJSの認知度を高められたらいいなと思いこの記事を書きました。

「ぼくがかんがえたさいきょうのReact」がこのSolidJSです。ぜひお試しください。


[^1]: [公式サイト](https://www.solidjs.com/)より引用。
[^2]:[仕組みの詳しい解説](https://indepth.dev/posts/1289/solidjs-reactivity-to-rendering#reactive-effects)
[^3]: [State of JS 2021の満足度部門](https://2021.stateofjs.com/en-US/libraries/front-end-frameworks/#front_end_frameworks_experience_ranking)にて、svelteと並び1位