如何在 React 组件中使用 switch 语句?

我有一个 React 组件,在组件的 render 方法中我有这样的东西:

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

           { switch(...) {} }

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

现在的重点是我有两个 div 元素,一个在顶部,一个在底部,它们是固定的。在中间我想要一个 switch 语句,并根据我状态中的一个值,我想渲染一个不同的组件。所以基本上,我希望两个 div 元素始终固定,并且每次都在中间渲染不同的组件。我正在使用它来实现多步骤付款程序)。虽然,正如目前的代码一样,它不起作用,因为它给了我一个错误,说 switch 是意外的。任何想法如何实现我想要的?

stack overflow How to use switch statement inside a React component?
原文答案
author avatar

接受的答案

试试这个,它也更干净:把那个开关从一个函数中的渲染中取出,然后通过你想要的参数调用它。例如:

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

答案:

作者头像

与其他答案相比,我更愿意在渲染函数中内联“开关”。它使在该位置可以渲染哪些组件更加清晰。您可以使用普通的旧 javascript 对象来实现类似 switch 的表达式:

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

正在发生这种情况,因为 switch 语句是 statement ,但这里的 javascript 需要一个表达式。

虽然不建议在 render 方法中使用 switch 语句,但您可以使用自调用函数来实现:

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

我在 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”函数中。这样我也可以整齐地缩进我的开关盒。

作者头像

我不是任何当前答案的忠实拥护者,因为它们要么过于冗长,要么需要您跳过代码才能了解发生了什么。

我更喜欢通过创建 <Switch/> 以更以react组件为中心的方式执行此操作。这个组件的工作是获取一个道具,并且只渲染子道具匹配这个的孩子。因此,在下面的示例中,我在开关上创建了一个 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>

您可以根据需要使切换变得简单或复杂。不要忘记对孩子及其价值道具进行更强大的检查。

作者头像

使用条件运算符在渲染块中表示一种 switch 的方法:

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

应确保条件严格返回布尔值。

作者头像

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
  }
}
作者头像

function Notification({ text, status }) {
  return (
    <div>
      {(() => {
        switch (status) {
          case 'info':
            return <Info text={text} />;
          case 'warning':
            return <Warning text={text} />;
          case 'error':
            return <Error text={text} />;
          default:
            return null;
        }
      })()}
    </div>
  );
}
作者头像

你可以做这样的事情。

 <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 />
    }
  }
作者头像

虽然这是 yet another way to do it ,但如果您已经全押,您可以利用 useCallback 来生成仅在必要时重新创建的函数。

假设您有一个组件应该根据 status 属性进行渲染。使用钩子,您可以按如下方式实现:

const MyComponent = ({ status }) => {
  const renderContent = React.useCallback(() => {
    switch(status) {
      case 'CONNECTING': 
        return <p className="connecting">Connecting...</p>;

      case 'CONNECTED': 
        return <p className="success">Connected Successfully!</p>

      default: 
        return null;

    }
  }, [status]);

  return (
    <div className="container">
      {renderContent()}
    </div>
  );
};

我喜欢这个,因为:

  • 很明显发生了什么 - 创建一个函数,然后调用(立即调用的匿名函数方法看起来有点奇怪,可能会混淆新开发人员)
  • useCallback 钩子确保 renderContent 回调在渲染之间被重用,除非依赖 status 改变
  • renderContent 函数使用闭包来访问传入组件的必要道具。一个单独的函数(如接受的答案)需要将道具传递给它,这可能很麻烦(尤其是在使用 TypeScript 时,因为参数也应该正确输入)