Reactコンポーネント内でswitchステートメントを使用するにはどうすればよいですか?


109

Reactコンポーネントがありrender、コンポーネントのメソッド内に次のようなものがあります。

render() {
    return (
        <div>
            <div>
                // removed for brevity
            </div>

           { switch(...) {} }

            <div>
                // removed for brevity
            </div>
        </div>
    );
}

ここで重要なのは、2つのdiv要素があり、1つは上部に、もう1つは下部に固定されているということです。途中でswitchステートメントが必要で、状態の値に応じて別のコンポーネントをレンダリングしたいと思います。したがって、基本的には、2つのdiv要素を常に修正し、その真ん中で毎回異なるコンポーネントをレンダリングする必要があります。私はこれを使用して、多段階の支払い手順を実装しています)。ただし、現在のコードと同様に、switch予期しないエラーが発生するため、機能しません。私が望むことを達成する方法について何かアイデアはありますか?


1
ええと、returnステートメントにそのすべてのロジックを含める必要はなくrender、そのことについてはメソッドさえも含める必要はありません。それぞれ<div>をconstとして定義し、switch before yourreturnを使用して、どちら<div>をレンダリングするかを決定できますか?
Jared Goguen 2017年

@JaredGoguenしかし、その後、のdiv各ケースで複数回、上部と下部でを繰り返す必要がありswitchます。または私はちょうど、あなたを誤解し...
タイプミス

いいえ、コードを作成してlet middleDiv = ...、そこでハードコーディングし{middleDiv}た2つ<div>の間のリターンJSXに含めることができます。
Jared Goguen 2017年

回答:


199

これも試してみてください。これも非常にクリーンです。関数のレンダリングからそのスイッチを取り出し、必要なパラメーターを渡して呼び出すだけです。例えば:

renderSwitch(param) {
  switch(param) {
    case 'foo':
      return 'bar';
    default:
      return 'foo';
  }
}

render() {
  return (
    <div>
      <div>
          // removed for brevity
      </div>
      {this.renderSwitch(param)}
      <div>
          // removed for brevity
      </div>
    </div>
  );
}


93

他の答えとは対照的に、私はレンダリング関数の「スイッチ」をインライン化することを好みます。その位置でどのコンポーネントをレンダリングできるかがより明確になります。プレーンな古いjavascriptオブジェクトを使用して、スイッチのような式を実装できます。

render () {
  return (
    <div>
      <div>
        {/* removed for brevity */}
      </div>
      {
        {
          'foo': <Foo />,
          'bar': <Bar />
        }[param]
      }
      <div>
        {/* removed for brevity */}
      </div>
    </div>
  )
}

1
これはかなりクールです。POJOの代わりに配列を使用するように少し変更し、インデックスを使用して配列にブラケットします。
ニコラスジェンタイル

1
これは、Pythonでswitch-caseを処理する標準的な方法です。この場合、読みやすさが優れているので、私はそれがより好きです。
私は

12
このアプローチには限界とオーバーヘッドがあります。各ビューが処理され、存在しない可能性のある現在の状態/小道具によって異なります。例:レンダリングしたいとしましょう:<SearchResults />または<NoResults />。ビューステートは、レンダリングする必要がある場合は<NoResults /><SearchResults />それがまだ存在しない性質に依存するため、コンパイルされない場合があります。
ABCD.ca

3
デフォルトの場合はどうですか?
lama12345

4
デフォルトのケースではlama12345 @、使用||などは次のとおりです。{ 'foo': <Foo />, 'bar': <Bar /> }[param] || <Baz />
アーロンエイドリアン

54

switchステートメントはであるためstatement、これが発生していますが、ここではjavascriptは式を想定しています。

renderメソッドでswitchステートメントを使用することはお勧めしませんが、自己呼び出し関数を使用してこれを実現できます。

render() {
    // Don't forget to return a value in a switch statement
    return (
        <div>
            {(() => {
                switch(...) {}
            })()}
        </div>
    );
}

おかげで私はそれを次のように使用しました:render(){return(<div> {(()=> {switch(this.state.type){case commons.HARD_SOFT:return <HardSoft params = {this.state.param} onSubmitHead = {this.onSubmit} />;}})()} </ div>);
JhonQO 2018

22

私はrender()メソッド内でこれを行いました:

  render() {
    const project = () => {
      switch(this.projectName) {

        case "one":   return <ComponentA />;
        case "two":   return <ComponentB />;
        case "three": return <ComponentC />;
        case "four":  return <ComponentD />;

        default:      return <h1>No project match</h1>
      }
    }

    return (
      <div>{ project() }</div>
    )
  }

render()の戻り値をクリーンに保とうとしたので、ロジックをすぐ上の「const」関数に配置しました。このようにして、スイッチケースをきれいにインデントすることもできます。


@a_m_devrenderメソッド内の「constproject」関数の代わりに、コンポーネントメソッドとして配置し、「<div> {this.project()} </ div>」のようにrenderreturn内で呼び出すことができます。スイッチをまったく使用しないという話でない限り、if / elseを使用するか、状態を更新してclassNameを使用してコンポーネントを表示/非表示にすることを考えることができます。
williamsi

たとえば、私が使用しているため、それは、もっと良いことができhead()て、データを注入するために、私のルートコンポーネントの方法をreact-helmet私の文書の頭に
a_m_dev

15

lenkanの答えは素晴らしい解決策です。

<div>
  {{ beep: <div>Beep</div>,
     boop: <div>Boop</div>
  }[greeting]}
</div>

デフォルト値が必要な場合は、

<div>
  {{ beep: <div>Beep</div>,
     boop: <div>Boop</div>
  }[greeting] || <div>Hello world</div>}
</div>

または、それがうまく読めない場合は、次のようなことを行うことができます

<div>
  { 
    rswitch(greeting, {
      beep: <div>Beep</div>,
      boop: <div>Boop</div>,
      default: <div>Hello world</div>
    }) 
  }
</div>

function rswitch (param, cases) {
  if (cases[param]) {
    return cases[param]
  } else {
    return cases.default
  }
}

2
{{key1:<Component1 />、...}[key]は良い解決策ではありません。ご覧の
とおり

ええ、スイッチは機能コンポーネントで使用されるべきではないので、lenkanの答えは正解であるはずです。デフォルトの場合はORを追加していただきありがとうございます。そして、rswitch()を気にしないでください、マップソリューションはスポットです!親指を立てる
EugenijusS.19年

15

条件演算子を使用して、レンダーブロックで一種のスイッチを表す方法:

{(someVar === 1 &&
    <SomeContent/>)
|| (someVar === 2 &&
    <SomeOtherContent />)
|| (this.props.someProp === "something" &&
    <YetSomeOtherContent />)
|| (this.props.someProp === "foo" && this.props.someOtherProp === "bar" &&
    <OtherContentAgain />)
||
    <SomeDefaultContent />
}

条件が厳密にブール値を返すことを確認する必要があります。


2
素晴らしくエレガントで、レンダーブロックで直接使用できます。ベストアンサーIMHO
GavinBelson

2
これはEsLintsルールの違反であることに気づきましたeslint.org/docs/rules/no-mixed-operatorsmixing&&と||
FishFingers

1
@FishFingers上記とまったく同じように使用しようとしたときにも気づきました。各「ケース」を括弧で囲むことで簡単に回避できます。
Ch0sen

13

私は現在の回答の大ファンではありません。冗長すぎるか、コードを飛び回って何が起こっているのかを理解する必要があるからです。

を作成することで、より反応性の高いコンポーネント中心の方法でこれを行うことを好み<Switch/>ます。このコンポーネントの仕事は、小道具を取り、子小道具がこれと一致する子のみをレンダリングすることです。したがって、以下の例testでは、スイッチに小道具を作成し、それをvalue子の小道具と比較して、一致するものだけをレンダリングしました。

例:

const Switch = props => {
  const { test, children } = props
  // filter out only children with a matching prop
  return children.find(child => {
    return child.props.value === test
  })      
}

const Sample = props => {
  const someTest = true
  return (
    <Switch test={someTest}>
      <div value={false}>Will display if someTest is false</div>
      <div value={true}>Will display if someTest is true</div>
    </Switch>
  )
}

ReactDOM.render(
  <Sample/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>

必要に応じて、切り替えを単純または複雑にすることができます。子供とその価値の小道具のより堅牢なチェックを実行することを忘れないでください。


3
まさに私が探していたものです!ここに少し改善があります:javascript const Switch = props => { const { test, children } = props; return children.find(child => { return child.props.value === test; }); }; const Case = ({ children, value }) => { return children; // I don't want do add container around my cases ! }; そのように書くことができます:javascript <Switch test={true}> <Case value={true}> <ItAlwaysFeelsRightToBeTrue /> </Case> <Case value={false}> <FalseAlarm /> </Case> </Switch>
lsmod

これは良い解決策ですが、コードに説明を追加すると、さらに良くなるでしょう
papigee

@papigeeもう少し詳細に更新されました。
マットウェイ

@MattWayこれは純粋なJSには適したオプションですが、ターゲットがes5に設定されていると、ReactNodeにプロパティ検索が存在しないためTSエラーがスローされます
Zakriya Bilal

@ZakriyaBilalコードは概念実証であり、スイッチのようなアイデアをコンポーネント化することで、コードがどのように反応するかについて説明しています。重要なのは、子供の小道具を比較する方法を見つけることです。
マットウェイ

3

どうですか:

mySwitchFunction = (param) => {
   switch (param) {
      case 'A':
         return ([
            <div />,
         ]);
      // etc...
   }
}
render() {
    return (
       <div>
          <div>
               // removed for brevity
          </div>

          { this.mySwitchFunction(param) }

          <div>
              // removed for brevity
          </div>
      </div>
   );
}

2

あなたはこのようなことをすることができます。

 <div>
          { object.map((item, index) => this.getComponent(item, index)) }
 </div>

getComponent(item, index) {
    switch (item.type) {
      case '1':
        return <Comp1/>
      case '2':
        return <Comp2/>
      case '3':
        return <Comp3 />
    }
  }

2

レンダリングにスイッチを設定することはできません。1つの要素にアクセスするオブジェクトリテラルを配置する疑似スイッチアプローチは、すべてのビューを処理し、その状態に存在しない小道具の依存関係エラーを引き起こす可能性があるため、理想的ではありません。

これは、各ビューを事前にレンダリングする必要がない、クリーンな方法です。

render () {
  const viewState = this.getViewState();

  return (
    <div>
      {viewState === ViewState.NO_RESULTS && this.renderNoResults()}
      {viewState === ViewState.LIST_RESULTS && this.renderResults()}
      {viewState === ViewState.SUCCESS_DONE && this.renderCompleted()}
    </div>
  )

ビューステートの条件が単純なプロパティ以上に基づいている場合(1行に複数の条件など)getViewState、条件をカプセル化する列挙型と関数は、この条件付きロジックを分離してレンダリングをクリーンアップするための優れた方法です。


シンプルでクリーンな方法。
AbhilekhSingh19年

2

これは、ボタンを使用してコンポーネントを切り替える完全な実例です。

次のようにコンストラクタを設定できます

constructor(props)
{
    super(props);
    this.state={
        currentView: ''
    }
}

次に、コンポーネントを次のようにレンダリングできます

  render() 
{
    const switchView = () => {

    switch(this.state.currentView) 
    {

      case "settings":   return <h2>settings</h2>;
      case "dashboard":   return <h2>dashboard</h2>;

      default:      return <h2>dashboard</h2>
    }
  }

    return (

       <div>

            <button onClick={(e) => this.setState({currentView: "settings"})}>settings</button>
            <button onClick={(e) => this.setState({currentView: "dashboard"})}>dashboard</button>

            <div className="container">
                { switchView() }
            </div>


        </div>
    );
}

}

ご覧のとおり、ボタンを使用して状態を切り替えています。


1

私はhttps://stackoverflow.com/a/60313570/770134の提案が本当に好きだったので、そのようにTypescriptに適合させました

import React, { FunctionComponent } from 'react'
import { Optional } from "typescript-optional";
const { ofNullable } = Optional

interface SwitchProps {
  test: string
  defaultComponent: JSX.Element
}

export const Switch: FunctionComponent<SwitchProps> = (props) => {
  return ofNullable(props.children)
    .map((children) => {
      return ofNullable((children as JSX.Element[]).find((child) => child.props['value'] === props.test))
        .orElse(props.defaultComponent)
    })
    .orElseThrow(() => new Error('Children are required for a switch component'))
}

const Foo = ({ value = "foo" }) => <div>foo</div>;
const Bar = ({ value = "bar" }) => <div>bar</div>;
const value = "foo";
const SwitchExample = <Switch test={value} defaultComponent={<div />}>
  <Foo />
  <Bar />
</Switch>;

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.