127
122

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

デザイナーでも分かる範囲のReact、その書き方と学び方

Last updated at Posted at 2021-04-08

これは何

  • 「デザイナーもReact書いてくださいよ」って空気になったときに読むと役立つかもしれない記事です
  • 基本的に筆者が学んだ流れを記載しています
    • そのため、世間一般のベストプラクティスではないと思います
    • エンジニアの方から見ると邪道な流れ・説明の仕方かもしれませんが、デザイナーに教える上での分かりやすさを重視していますのでご了承ください
  • この記事の中で使っているコードはこちらのリポジトリで公開しています
    • コミットを辿ってもらえれば、各セクションの内容が全て見れます
  • ※言い訳がましいですが、筆者もReactに精通している程ではなく「デザイナーにしては割と知ってる」レベルです
    • もし説明に間違いや不足があれば編集リクエストをお願いします :pray:

対象読者

  • Web or UIデザイナー
  • HTMLとCSSは普通に書けるけど、Reactはほぼ全く触ったことがない人
  • 1人で完全に実装したいってほどではないけど、簡単な部分は書けるようになりたいと思っている人
  • メイン対象はデザイナーなものの、初心者向けの内容ではあるので「新人プログラマ」も対象になるかもしれません

筆者はどんな人

普段の業務ではUIのモックアップを作って、ある程度はReactでのコーディングもしています。
また、業務レベルではありませんが自分のポートフォリオサイトは全てReactで書いています。

Reactの概念について

概念を説明するといっても、深い部分までは扱いません。
あくまでデザイナー向け、かつ、不慣れな人でもパンクしない程度の内容にとどめます。

上記の関係で「Reactに限らない説明」も多いです。

コンポーネントを組み合わせてインターフェースを作成できる

  • ボタン・タブ・リスト……UIの種別を問わず、一度定義すればそれを繰り返し使える
    • 同じものを何回も作らなくて良い
  • FigmaやSketchなどのツールを用いてインターフェースを作るときの考え方と非常に似ている1
    • 慣れれば、UIツール上でコンポーネントを作っている最中に、コードでのコンポーネントの実装方法も想像できる

色々な場所が変化するインターフェースを作成しやすい

  • HTMLやCSSだけでサイトを作るのはかなり大変
    • 「ログインしていたら」とか「商品を買い物かごに入れていたら」といった、任意の条件にあわせたインターフェースの変化は上手く表現できない
    • HTMLだけだったら「登録されているユーザー情報を100人分表示する」場面では100回繰り返して書く必要がある
    • それ以外にも色々……
  • Reactなら上記の「条件の違い」や「繰り返し」も表現できる2
    • HTMLやCSSだけではできないことができるようになる
    • 効率の良いコードを書けるようになる

Reactを触っていく順番

公式のチュートリアルとは全然違う順番ですが、デザイナーならこういう順番で触れるのが良いのではないでしょうか。

私がいつも伝える上で大事にしているのは「何も分からない……」と諦めの感情を抱かせないようにすることです。
「完全に理解した」と調子に乗るのも良くありませんが「意外と理解できる、楽しいぞ!」と思えるのが重要だと思います。

HTMLもどきとCSSもどきだけを触れるようになる

デザイナーもReactを触ると言っても、最初のうちはHTMLもどきとCSSもどきを触れるようになるだけでも十分かと思います。
簡単なスタイル調整や文言の修正をエンジニアから巻き取れるだけでも、チームの作業スピードは上がるんじゃないでしょうか。

それにしてももどきってなんだよって話ですよね。
細かい説明をしだすと難しくなるので、実際のコードを見てください。

Create React Appというスターターキットのようなものがあり、そこで生成されるコードをアレンジして例に出します。

App.js
import logo from './logo.svg';
import './App.css';

const firstName = "John"
const lastName = "Doe"
const fullName = `${firstName} ${lastName}`

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Hello, {fullName}
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

Hello, John Doeと書かれた画面のスクリーンショット

見た目はこんな感じです。

App.jsにおいてimportconstfunctionexportは見慣れないかもしれません。
しかしreturn以降は見覚えがありますよね?

そう、ほぼHTMLなんです。

現段階で微妙にHTMLと違うのは以下の2点のみ。

  1. classではなくclassNameと書かれている
  2. imgタグのsrcや、pタグの中で{}を使って書かれている箇所がある({logo}{userName}

classNameについて

Reactの世界ではclassという単語はCSS以外の場所で使われています。
そのためCSSのクラス名を指定する際には、classではなくclassNameと書く必要があります
若干違和感を覚えるかもしれませんが、これは暗記するしかありません。

ちなみに似た話でlabelinputを紐付ける際に、HTMLではforを使いますが、ReactではhtmlForを使います。
こちらも違和感はあると思いますが「Reactではそうやって書くんだな」と割り切って覚えていただきたいです。

ここで「冒頭で出ていた『CSSもどき』ってclassclassNameに変わるだけってこと?」と思われる方もいるかもしれません。
半分正解で、半分不正解です。
Reactにおいてスタイリングを施す方法はかなりたくさんあるため、一概には言えないのです。

例えば「font-sizeが20pxで赤色の文字」をスタイリングするだけでも、次のような方法があります。

例1 インラインスタイル
例1
// インラインスタイル
function Example1() {
  return (
    <p style={{ fontSize: 20, color: "#f00" }}>スタイリングの例</p>
  )
}
例2 普通のCSSやSassを使う
例2
// React側のコード
import './style.css'

function Example2() {
  return (
    <p className="foo">スタイリングの例</p>
  )
}
例2
/* CSS側のコード */
.foo {
  font-size: 20px;
  color: #f00;
}
例3 CSS Modulesを使う
例3
// React側のコード
import styles from './style.css'

function Example3() {
  return (
    <p className={styles.foo}>スタイリングの例</p>
  )
}
例3
/* CSS側のコード */
.foo {
  font-size: 20px;
  color: #f00;
}
例4 CSS in JSを使う(ここではEmotion)
例4
import { css } from "@emotion/react"

function Example4() {
  return (
    <p css={foo}>スタイリングの例</p>
  )
}

const foo = css({
  fontSize: 20,
  color: "#f00"
})

たくさん例を出しましたがビビらせたい訳ではありません。
この例以外にもまだまだ色々な書き方があり、網羅的に説明するのが難しいことをお伝えしたいだけです。

更に言えば例1~4を見て頂ければ分かるとおり、それぞれ微妙に書き方は違うものの「ほぼCSS」ですよね?
そのため、使っているものさえ分かれば後は慣れるだけです。

「ウチってスタイリングには何を使ってるんですか?」と聞けば、エンジニアのみなさんが教えてくれることでしょう。

{}の使用について

HTMLを書いていて、{}が何かの役割を担うことはありませんよね?
ですが、Reactにおいては大活躍します。

HTMLもどきの中で{}が出てきたら「このカッコの中ではJavaScriptが動いているんだな」と捉えてください。

imgタグでは

<img src={logo} className="App-logo" alt="logo" />

と書いてありますが、先ほどのコードの1行目には

import logo from './logo.svg';

と書いてあります。

これらを踏まえてimgタグに書いてある内容をHTMLに翻訳(?)すると以下のようになります。

<img src='./logo.svg' className="App-logo" alt="logo" />

'./logo.svg'の場所にあるファイルを{logo}という書式で呼び出せるようになっているんですね。

また、コードの最初の方には以下の記述があります。

const firstName = "John"
const lastName = "Doe"
const fullName = `${firstName} ${lastName}`

こちらを日本語訳するとこんな感じです。

Johnという文字列をfirstNameという定数に突っ込みます
Doeという文字列をlastNameという定数に突っ込みます
firstNameとlastNameを合体させた文字列をfullNameという定数に突っ込みます

そしてfullNameは実際にはこのように使われています。

<p>
  Hello, {fullName}
</p>

コードではこう書かれていますが、スクリーンショットを見るとHello, John Doeと表示されています。

Hello, John Doeと書かれた画面のスクリーンショット

{}で囲われたfullNameがJavaScriptとして動き、firstNamelastNameの合体したもの、つまりJohn DoeとしてHTMLに表れているのです。

ここまでのまとめ

  • デザイナーがReactを触り始めるなら、まずはHTMLもどきとCSSもどきを触れれば十分
  • HTMLもどきはclassNameだけは暗記しておきましょう
  • CSSもどきは色々な種類があるから身近にいるエンジニアに聞きましょう
  • {}が出てきたら、今はひとまず「このカッコの中ではJavaScriptが動いているんだな」と理解できれば大丈夫

コンポーネントを使えるようになる

HTMLもどきとCSSもどきはだいたい触れるようになったとします。

お次は、最初の方で出したメリットの「コンポーネントを組み合わせてインターフェースを作成できる」を享受できるようになりましょう。

とりあえず作ってみる

まずは、新しくSomeComponentという名前のコンポーネントを作ってみます。

SomeComponent.js
function SomeComponent() {
  return (
    <p style={{ fontSize: 20, color: '#61dafb' }}>This is example component</p>
  )
}

export default SomeComponent

export default SomeComponentと書いてあるのは「よそのファイルでもSomeComponentを使えるようにします!」って言ってるような雰囲気で捉えてください。
そのため、これを書き忘れると他のファイルで使い回せなくなってしまいます。

例なのでそう大したことはしていませんが、フォントサイズと色とテキストを定義したコンポーネントです。
これらの組み合わせはしょっちゅう使い回す場合、毎回同じHTMLとCSSを書くのは手間ですが、Reactなら1回ここで定義すれば後は何度でも使い回せます。

先ほど例で使っていたコードを少し改変して、SomeComponentを利用してみましょう。

App.js
import logo from './logo.svg';
import './App.css';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import SomeComponent from './SomeComponent'

const firstName = "John"
const lastName = "Doe"
const fullName = `${firstName} ${lastName}`

function App() {
  return (
    <Router>
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Hello, {fullName}
          </p>
          <Switch>
            <Route path="/about">
              <About />
            </Route>
            <Route path="/users">
              <Users />
            </Route>
            <Route path="/">
              <Home />
            </Route>
          </Switch>
          <ul className="linkList">
            <li className="linkItem">
              <Link to="/" className="link">Home</Link>
            </li>
            <li className="linkItem">
              <Link to="/about" className="link">About</Link>
            </li>
            <li className="linkItem">
              <Link to="/users" className="link">Users</Link>
            </li>
          </ul>
        </header>
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return (
    <>
      <h2>About</h2>
      <SomeComponent />
    </>
  );
}

function Users() {
  return (
    <>
      <h2>Users</h2>
      <SomeComponent />
    </>
  );
}

export default App;

※途中でSwitchとかRouteとか出てきていますが、無視して大丈夫です。

Home About Users
Homeの画面 Aboutの画面 Usersの画面

ページが3つあり、/home/about/usersだとします。
そして/about/usersでは20pxで#61dafbの色のThis is example componentという文字列、つまりSomeComponentを使い回したいとします。

App.jsの最初の方で、SomeComponentを呼び出していますね

App.js
import SomeComponent from './SomeComponent'

そして後の方で、繰り返し使っています。

App.js
function About() {
  return (
    <>
      <h2>About</h2>
      <SomeComponent />
    </>
  );
}

function Users() {
  return (
    <>
      <h2>Users</h2>
      <SomeComponent />
    </>
  );
}

これにより、/about/usersでは見出しの下に同じサイズと色のテキストを呼び出すことができました。

オーバーライドできるようにする

FigmaやSketchでは、ボタンやタブやリストなど、よく使い回すものはコンポーネント(or シンボル)として定義して適宜オーバーライドしながら使っていますよね。
もちろんReactでも可能です。

先ほど作ったSomeComponentのテキストをオーバーライドできるようにしてみましょう。

- function SomeComponent() {
+ function SomeComponent({ text }) {
    return (
-     <p style={{ fontSize: 20, color: '#61dafb' }}>This is example component</p>
+     <p style={{ fontSize: 20, color: '#61dafb' }}>This is {text} component</p>
    )
  }

  export default SomeComponent

まず、先ほどまではfunction SomeComponent()だったのがfunction SomeComponent({ text })と変わっています。

これは「textって名前のデータを受け取ってきて使います」というニュアンスです。

そしてpタグの中のテキストがThis is example componentからThis is {text} componentに変わっていますね。
これは「さっき受け取ってきたtextの中身をここに表示します!」という感じです。

コンポーネントを更新できたら、App.jsも更新します。

  function About() {
    return (
      <>
        <h2>About</h2>
-       <SomeComponent />
+       <SomeComponent text="about" />
      </>
    );
  }

  function Users() {
    return (
      <>
        <h2>Users</h2>
-       <SomeComponent />
+       <SomeComponent text="users" />
      </>
    );
  }

2つのSomeComponentの中で、それぞれ違うテキストを渡しています。
すると表示は以下のようになります。(見づらいので拡大してご覧ください :pray:

About Users

aboutの文字を渡した方はThis is about componentに、
usersの文字を渡した方はThis is users componentになっているのがお分かりでしょうか?

もちろん文字以外にも色やサイズやレイアウトなど、色々なオーバーライドができます。
FigmaやSketchでできるオーバーライドはReactならなんでもできるので、興味を持ったら是非色々調べてみてください。

ここまでのまとめ

  • 新規にファイルを作って「他のファイルでも使えるようにします」と宣言すればいつでも使い回せる
  • 日頃FigmaやSketchで行っているようなオーバーライドもコードで実現できる

? :とか&&とかの書き方を理解してマークアップ・スタイリングができる

このくらいの時期になるとエンジニアが書いたコードを見て、謎の記号の組み合わせをたくさん発見するのではないでしょうか?

  • ? :
  • &&
  • ||

何が書いてあるかも良く分からないし、ググろうにもなんてググったら良いか分からないのではないでしょうか。
実はちゃんと名前があります。

  • ? : → 三項演算子
  • && || → ショートサーキット評価(短絡評価)

難しく見えますが、ちょっとしたスタイリングの出し分けや要素の出し分けを検証するときに、デザイナーもこれが理解できていると非常に便利です。

よくある使い方を記載します。

? :

よくあるコードは、だいたいこんな感じです。
checkedは、どこかで別に宣言されていて「チェックされているか否か」を判断する役割のものだと思ってください。

checked ? <OkIcon /> : <NgIcon />

これを日本語訳すると「チェックされてたらOkIconコンポーネントを、されてなかったらNgIconコンポーネントを表示する」といった具合です。

一般化するとA ? B : Cは、AがあればBを、なければCを出すです。

&&

よくあるコードは、だいたいこんな感じです。
errorはどこかで別に宣言されていて「エラーが発生しているか否か」を判断する役割のものだと思ってください。

error && <ErrorMessage />

これを日本語訳すると「エラーがあるときだけErrorMessageを表示する」といった具合です。

一般化するとA && Bは、AがあればBを出す、Aがなければ何もしないです。

||

よくあるコードは、だいたいこんな感じです。
currentValueはどこかで別に宣言されていて「現在の値」が入っていると思ってください。

currentValue || 10

これを日本語訳すると「currentValueがあればそれを、なければ10を表示する」といった具合です。

一般化するとA || Bは、AがあればAを出す、AがなければBを出すです。

ここで紹介した記号の書き方を駆使して自分だけでコードを書くのは難しいかもしれません。
ですが、現状の条件分岐が分かるだけでも、HTMLもどきやCSSもどきの編集によって進められるタスクは結構あるはずです。

また、foo && bar < 10 && baz === 'yes' && <Component />のように複雑になっている場合もありますが、焦らず1つずつ読み解いていきましょう。

ここまでのまとめ

  • 謎に見える記号の集まりも、ちゃんと名前もルールもある
  • 若干アバウトな説明になるものの
    • A ? B : Cは、AがあればBを、なければCを出す
    • A && Bは、AがあればBを出す、Aがなければ何もしない
    • A || Bは、AがあればAを出す、AがなければBを出す

ダミーのStateを作って条件にあわせたマークアップ・スタイリングができる

最後です。これは結構難しく感じるかもしれませんがとても有用だと思います。

「条件をクリアしているときはAの見た目、そうでないときはBの見た目のボタンを作りたい」のようなことを考えるシーン、ありますよね?

完全な条件を実装するのは無理でも、手元でおおよその動きを検討してエンジニアに引き継ぐことはできます。

また先ほどのコードを改造して例に出します。

App.js
import logo from './logo.svg';
import './App.css';
import { useState } from 'react'
import AnotherComponent from './AnotherComponent'

const firstName = "John"
const lastName = "Doe"
const fullName = `${firstName} ${lastName}`

function App() {
  const [status, setStatus] = useState(true)
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Hello, {fullName}
        </p>
        <AnotherComponent status={status} onClick={() => setStatus(!status)} />
      </header>
    </div>
  );
}

export default App;

コンポーネントを扱う話で出したのと同様に、AnotherComponentをimportしています。

import AnotherComponent from './AnotherComponent'

その後、returnの中でAnotherComponentを使用しているのですが、なんだか難しい雰囲気になっていますね。

<AnotherComponent status={status} onClick={() => setStatus(!status)} />

このあたりの仕組みを解説します。
じつはAnotherComponentを呼び出すより上で、useStateというものを呼び出しています。

import { useState } from 'react'

これが何かを最初から理解しようとすると混乱のもとなので、今は「そういうものがあるのか」ぐらいで大丈夫です。

そしてfunction App()のすぐ下で、これまた初めて見る書き方のものがあります。

const [status, setStatus] = useState(true)

これも最初は書き方を真似ればOKです。
今は[foo, setFoo] = useState(初期値)という書式だけ覚えてください。

どんな名前をつけても良いですが、fooとつけたならsetFooだしbarと名付けたならsetBarにするのが1つ。
useStateの初期値はなんでもありですがデザイナーの範疇だとtruefalseかを入れておけば事足りる場合が多いです。

条件にあわせて変わるスタイルを組む、差し当たって、最初は条件をクリアしているのかいないのか、ぐらいの考え方でOKです。
デフォルトで条件をクリアしているようなものだったらtrueを、デフォルトではクリアしていなさそうだったらfalseを与えてあげてください。

そして話が若干前後しますがAnotherComponentにおいては

<AnotherComponent status={status} onClick={() => setStatus(!status)} />

日本語訳すると「さっき定義したstatusのデータを渡す。クリックした場合はstatustruefalseを入れ替える」ようなイメージです。

じゃあAnotherComponent自体のコードはどうなっているのかというと、以下です。

AnotherComponent.js
import './App.css';

function AnotherComponent({ status, onClick }) {
  return (
    <button
      className={`button ${status ? 'button--ok' : 'button--ng'}`}
      onClick={onClick}
    >
      Status is {status ? 'OK' : 'NG'}
    </button>
  )
}

export default AnotherComponent

ひとつずつ解説すると

function AnotherComponent({ status, onClick })

statusonClickというデータを受け取ります」と宣言していて

<button
  className={`button ${status ? 'button--ok' : 'button--ng'}`}
  onClick={onClick}
>

「クラス名は、いつでもbuttonがついている。さっき受け取ったstatustrueだったらbutton--okというクラス名を、falseだったらbutton--ngというクラス名をつける」
「ボタンをクリックしたときは、さっき受け取ったonClickが発動する。つまり、クリックしたときにstatustruefalseを入れ替える動きをする。」

これらが全部あわさると、クリックするたびボタンのラベルと色が変わる実装ができます。

ボタンのラベルと色が変わる様子

条件にあわせたクラスの付け替えやアニメーション実装などができたら、エンジニアに引き継いで「実際の条件分岐」を適用してもらいましょう。

デザイナーは、スタイリングは得意だけど条件をつけたりするのが苦手。
エンジニアは、条件をつけるのは余裕だけどスタイリングは苦手。
という傾向があります。

そこを、仮の条件分岐でもデザイナーがスタイリングすることで、連携がしやすくなるはずです。

ここまでのまとめ

  • useStateというものを使うと、コードは少なめでも色々な状態を実現できる
  • 実際のプロダクトに即していなくても、UIの状態変化を手元で再現することができる
  • デザイナーだけで完成させるための手立てというよりはエンジニアと上手く協力するための知識

まとめ

  • HTMLとCSSだけじゃできないことも、Reactならできる
  • ほとんどHTMLとCSSの知識で書ける箇所もある
  • プラスαで覚えられれば、コードを読むときの迷いが減ったり、エンジニアとの連携がしやすくなる
  1. UIツールに実装されるよりも前から、プログラミングの世界にはコンポーネントのような概念がありました。デザイナーの方が後発です。(念のため補足)

  2. これはReactに限らない話。

127
122
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
127
122

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?