28
33

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 5 years have passed since last update.

Reactがちょっといい感じになる書き方メモ

Posted at

https://reactjs.org/ を見て、気になった書き方・機能をまとめていきます。

Inline If with Logical && Operator

特定の条件の場合のみ表示する、というシチュエーションはよくあります。

例えば、エラーが存在する場合のみ、エラーメッセージを表示するなど。

普通に書くと、下記のようになる。

class App extends Component {
  render() {
    let errorMessage = "XXX is required."; // or null

    let errorMessageTag = null;
    if (errorMessage) {
      errorMessageTag = <p className="App-intro">error:{errorMessage}</p>
    }

    return (
      <div>
        {errorMessageTag}
      </div>
    );
  }
}

https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator を見ると、下記のように書けるようです。

class App extends Component {
  render() {
    let errorMessage = "XXX is required."; // or null

    return (
      <div>
        {errorMessage &&
          <p className="App-intro">error:{errorMessage}</p>
        }
      </div>
    );
  }
}

Preventing Component from Rendering

ただ、上記のような場合は、別コンポーネントにしたほうが良さそうです。
https://reactjs.org/docs/conditional-rendering.html#preventing-component-from-rendering

function ErrorMessage(props) {
  if (!props.errorMessage) {
    return null;
  }

  return (
    <div>error:{props.errorMessage}</div>
  );
}

class App extends Component {
  render() {
    let errorMessage = "XXX is required."; // or null

    return (
      <div>
        <ErrorMessage errorMessage={errorMessage} />
      </div>
    );
  }
}

ErrorMessage はタグ名になるのでUpperCamelCaseになりますが、functionでもあるのでちょっと気持ち悪い。)

Inline If-Else with Conditional Operator

特定の条件によってAとBの表示を切り替える、というシチュエーションもよくあります。

例えば、「ログインボタン」と「ログアウトボタン」を切り替えたり。

そのまま書くと、下記のようになる。

class App extends Component {
  render() {
    let flag = true;

    let sample = null;
    if (flag) {
      sample = <p className="App-intro">Hoge.</p>;
    } else {
      sample = <p className="App-intro">Fuga.</p>;
    }

    return (
      <div>
        {sample}
      </div>
    );
  }
}

https://reactjs.org/docs/conditional-rendering.html#inline-if-else-with-conditional-operator を見ると、もっと手軽に書けそうです。

class App extends Component {
  render() {
    let flag = false;

    return (
      <div>
        {flag ? (
          <p className="App-intro">Hoge.</p>
        ) : (
          <p className="App-intro">Fuga.</p>
        )}
      </div>
    );
  }
}

Specialization

Dialogなどは、外枠が共通で、中身が「タイトルだけ」だったり「メッセージに装飾がついてる」だったり「ボタンが複数」だったりします。
そんなときは、 children という特別なpropを使うようです。

function Dialog(props) {
  const style = {
    backgroundColor: "#ff0000",
    margin: "10px"
  };
  return <div style={style}>{props.children}</div>;
}

class App extends Component {
  render() {
    return (
      <div>
        <Dialog>メッセージのみ</Dialog>
        <Dialog>
          <span>ボタンもあるイメージ</span>
          <button href="alert('test');">OK</button>
        </Dialog>
      </div>
    );
  }
}

Using Dot Notation for JSX Type

https://reactjs.org/docs/jsx-in-depth.html#using-dot-notation-for-jsx-type
このリンクにあるように、<MyComponents.DatePicker />みたいにモジュール化?できます。

プロジェクト内の汎用のコンポーネントを MyComponents の中に入れておき、そこから画面ごとのコンポーネントを作成する、とかもいいかもしれません。

Choosing the Type at Runtime

https://reactjs.org/docs/jsx-in-depth.html#choosing-the-type-at-runtime
動的に表示するタグを決めることも出来ます。

便利そうですが、使い所は思いついていないです。

const Sample1 = () => <div>This is Sample1.</div>;
const Sample2 = () => <div>This is Sample2.</div>;

class App extends Component {
  render() {
    let flag = true; // or false
    const Hoge = flag ? Sample1 : Sample2;
    return (
      <div>
        <Hoge />
      </div>
    );
  }
}

Spread Attributes

... を使うと、objectを展開してパラメータにすることができるようです。
例えば、次の2つは同じ結果になります。

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

それ以外にも、一部(この場合はkind)を消化して、それ以外を子要素に渡すといったこともできそうです。

const Button = props => {
  const { kind, ...other } = props;
  const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
  return <button className={className} {...other} />;
};

const App = () => {
  return (
    <div>
      <Button kind="primary" onClick={() => console.log("clicked!")}>
        Hello World!
      </Button>
    </div>
  );
};

ただ、安易にこれを使いすぎると、どのパラメータが必要・有効なのかが分からなくなってしまいそうです。
(そのために、FlowやTypeScriptで型定義をしておいたほうがいいかも?)

Children in JSX - String Literals

HTMLとしてのみやすさを重視すると、タグ直後や途中で改行を入れたくなります。
ただ、通常のHTMLでは改行・スペースが反映されてしまい、レイアウトが崩れる場合がありました。

JSXでは、改行やスペースを削除してくれるようです。
そのため、下記は同一のHTMLとしてレンダリングされます。

class App extends Component {
  render() {
    return (
      <div>
        <div>Hello World</div>

        <div>
          Hello World
        </div>
      </div>
    );
  }
}

Refs and the DOM

フォーカスや文字の選択などの、DOMの直接操作が必要な事態は出てきます。

そのために、idを振って、document.getElementById('foo')としてDOMを取得することは出来ます。
Reactでは、同様のことをrefを使って実現できます。

class App extends Component {
  constructor(props) {
    super(props);
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    this.textInput.focus();
  }

  render() {
    return (
      <div>
        <input
          type="text"
          ref={input => {
            this.textInput = input;
          }}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

Fragments

Reactのcomponentは、特定のタグの下に置く必要があります。
なので、下記のような書き方は出来ません。

const Sample0 = () => (
  This is <span style={{ color: "#f00" }}>Sample1</span>.
);

ただ、<div>タグが必要ない場合もあります。<React.Fragment>を使えば、実現できるようです。

const Sample1 = () => (
  <React.Fragment>
    This is <span style={{ color: "#f00" }}>Sample1</span>.
  </React.Fragment>
);

const Sample2 = () => (
  <div>
    This is <span style={{ color: "#f00" }}>Sample2</span>.
  </div>
);

class App extends Component {
  render() {
    return (
      <div>
        <Sample1 />
        <Sample2 />
      </div>
    );
  }
}

レンダリング結果は下記のようになります。

<div>
  This is <span style="color: rgb(255, 0, 0);">Sample1</span>.
  <div>This is <span style="color: rgb(255, 0, 0);">Sample2</span>.</div>
</div>

まとめ

こんな感じで、いろいろな書き方があるので、それらを駆使して読みやすいコードを心がけていきたいですね。

28
33
0

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
28
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?