Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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を使うようです。

https://reactjs.org/docs/composition-vs-inheritance.html#specialization

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

https://reactjs.org/docs/jsx-in-depth.html#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

https://reactjs.org/docs/refs-and-the-dom.html

フォーカスや文字の選択などの、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

https://reactjs.org/docs/fragments.html

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>

まとめ

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away