背景
筆者は実務で約1年半Vue.jsの開発をしています。Reactは記事でも見ることが多く、SPAといえばReactが一番に出てくるけれど、Reactを一才触ったことがなかったです(結局リアクティブだからそんな違いはないだろうと思うのもあってあまり触っていなかった)。とはいえ、よく聞くReactを一切触っていないのも怖く、その勉強がてらチュートリアルをやってみました。以下の比較は主に、Vue.js options API と React Hook を比較しています。
筆者はReactについてほとんど知らないです。(クラスコンポーネントと関数コンポーネントの違いを最近知ったくらい)
Reactのチュートリアルが新しくなっていました。React hookを前提とした内容になっています。
親コンポーネントのデータ書き換え
Vue.jsで親コンポーネントのデータを子コンポーネントから変更する際は emit
を使用してデータを書き換えます。一方でReactでは、prop
でデータを書き換える無名関数(クロージャー)を渡すことでデータを書き換えます。Vue.jsでは、prop
で無名関数を渡すことは、コンポーネントの依存性が高まるため推奨されていません。
比較コード(親コンポーネントのcountを子コンポーネントから増加させる)
const ParentComp = {
template: `
<child-comp
:count="count"
@set-count="count + 1"
></child-comp>
`,
data() {
return {
count: 0
}
},
components: [ChildComp]
}
const ChildComp = {
props: ["count"],
emits: ["setCount"],
template: `
<button @click="$emit('setCount')">
Clicked {{ count }} times
</button>
`
}
function ParentComp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<ChildComp count={count} onClick={handleClick} />
</div>
);
}
function ChildComp({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
繰り返しの表示
Reactでは、JSXと言うマークアップ構文を使用することで簡単にテンプレートを変数に入れることができ、それを表示することができます。Vue.jsでは、template内でfor文を書いて実装します。React同じようにやろうと思えばできますが無駄な処理が多くなります。
比較コード(食べ物がリストで並んでいるコンポーネント)
const ProductsComp = {
template: `
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }}
</li>
</ul>
`,
data() {
return {
products: [
{id: 1, name: "apple"},
{id: 2, name: "banana"}
]
}
},
}
function ProductsComp() {
const products = [
{id: 1, name: "apple"},
{id: 2, name: "banana"}
]
const listItems = products.map(product =>
<li key={product.id} >
{product.name}
</li>
);
return (
<ul>{listItems}</ul>
);
}
マークダウン構文
Vue.jsでは、bindを使用してtemplate内に表示したいマークアップを書きます。Reactでは、JSXと言うマークアップ構文を使用することで、関数コンポーネントがマークアップを返却することができ、より自由度が増しているように感じました。
比較コード(視聴済みか未視聴かで表示するテキストを切り替える)
const TitleComp = {
template: `
<template v-if="isWatched">
<p>watched</p>
</template>
<template v-else>
<p>unwatch</p>
</template>
`,
data() {
return {
isWatched: false
}
}
}
function TitleComp() {
const [isWatched, toWatched] = useState(false);
if (isWatched) {
return (
<p>watched</p>
)
} else {
return (
<p>unwatch</p>
)
}
}
やってみた感想
Vue.jsをある程度やっていると、参入障壁は非常に低いと思いました。コンポーネント間のデータのやり取りの考えがわかっていると特に困ることはないと思います。
チュートリアルの内容とは関係ないのですが、ページの表示が早く感じました。Next.jsを使用しているので、SSG機能を使用しているかな?Next.jsを書いたことがないので今後やってみたい。
Qiitaの折りたたみが書きずらすぎた。