Как использовать оператор switch внутри компонента React?

У меня есть компонент React, а внутри метода render компонента у меня есть что-то вроде этого:

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

           { switch(...) {} }

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

Теперь дело в том, что у меня есть два элемента div, один сверху и один внизу, которые фиксированы. В середине я хочу иметь оператор switch, и в соответствии со значением в моем состоянии я хочу отобразить другой компонент. Поэтому в основном, я хочу, чтобы оба элемента div были исправлены всегда, и только посередине, чтобы каждый раз отображать разные компоненты. Я использую это для реализации многоступенчатой процедуры оплаты). Хотя, как и в настоящее время код не работает, поскольку он дает мне ошибку, говоря, что switch неожиданен. Любые идеи, как достичь того, чего я хочу?

Ответы

Ответ 1

Попробуйте это, что также является более чистым: получите этот переключатель из рендеринга в функции и просто назовите его передачей параметров, которые вы хотите. Например:

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>
  );
}

Ответ 2

Это происходит, потому что оператор switch является statement, но здесь javascript ожидает выражение.

Хотя, не рекомендуется использовать оператор switch в методе render, вы можете использовать функцию self-invoking для достижения этого:

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

Ответ 3

В отличие от других ответов, я предпочел бы включить "переключатель" в функцию рендеринга. Это делает более понятным, какие компоненты могут быть сделаны в этом положении. Вы можете реализовать выражение, подобное выражению, используя простой старый объект javascript:

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

Ответ 4

Способ представления вида регистра переключателя в блоке рендеринга с использованием условных операторов:

{this.props.someVar == 1 &&
    <SomeContent/>
|| this.props.someVar == 2 &&
    <SomeOtherContent />
|| this.props.someOtherVar == 1 &&
    <YetSomeOtherContent />
||
    <SomeDefaultContent />
}

Я советую добавить несколько скобок, чтобы быть уверенным в ожидаемом результате, если только вы не освоите приоритет операторов...

Ответ 5

Я сделал это внутри метода 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 прямо выше. Таким образом, я могу аккуратно делать отступы в своих переключателях.

Ответ 6

Как насчет:

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>
   );
}

Ответ 7

Ответ от 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
  }
}

Ответ 8

Вы можете сделать что-то подобное.

 <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 />
    }
  }

Ответ 9

Вы не можете иметь переключатель в рендере. Подход psuedo-switch для размещения объекта-литерала, который обращается к одному элементу, не идеален, потому что он вызывает обработку всех представлений, что может привести к ошибкам зависимости реквизитов, которые не существуют в этом состоянии.

Вот хороший чистый способ сделать это, который не требует, чтобы каждое представление отрисовывалось заранее:

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>
  )

Если ваши условия, для которых состояние просмотра основано на чем-то большем, чем простое свойство - например, несколько условий на строку, тогда enum и функция getViewState для инкапсуляции условий - хороший способ отделить эту условную логику и очистить ваш рендеринг.

Ответ 10

Это другой подход.

render() {
   return {this['renderStep${this.state.step}']()}

renderStep0() { return 'step 0' }
renderStep1() { return 'step 1' }