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

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

           { switch(...) {} }

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

Now the point is that I have two div elements, one at the top and one at the bottom, that are fixed. In the middle I want to have a switch statement, and according to a value in my state I want to render a different component. So basically, I want the two div elements to be fixed always, and just in the middle to render a different component each time. I'm using this to implement a multi-step payment procedure). Though, as is the code currently it doesn't work, as it gives me an error saying that switch is unexpected. Any ideas how to achieve what I want?


当前回答

试试这个,它也更干净:在一个函数中获得渲染的开关,并调用它传递你想要的参数。例如:

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

其他回答

这个答案专门用来解决@tonyfat提出的“重复”问题,关于如何使用条件表达式来处理相同的任务。


Avoiding statements here seems like more trouble than it's worth, but this script does the job as the snippet demonstrates:

// Runs tests let id = 0, flag = 0; renderByFlag(id, flag); // jobId out of range id = 1; // jobId in range while(++flag < 5){ // active flag ranges from 1 to 4 renderByFlag(id, flag); } // Defines a function that chooses what to render based on two provided values function renderByFlag(jobId, activeFlag){ jobId === 1 ? ( activeFlag === 1 ? render("A (flag = 1)") : activeFlag === 2 ? render("B (flag = 2)") : activeFlag === 3 ? render("C (flag = 3)") : pass(`flag ${activeFlag} out of range`) ) : pass(`jobId ${jobId} out of range`) } // Defines logging functions for demo purposes function render(val){ console.log(`Rendering ${val}`); } function pass(reason){ console.log(`Doing nothing (${reason})`) }

我真的很喜欢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>;

我不太喜欢当前的任何答案,因为它们要么太啰嗦,要么需要您在代码中跳跃才能理解发生了什么。

我更喜欢用一个更以react组件为中心的方式来做这件事,通过创建一个<Switch/>。这个组件的任务是获取一个道具,并且只呈现子道具与该道具匹配的子元素。所以在下面的例子中,我在开关上创建了一个测试道具,并将其与子节点上的值道具进行比较,只渲染匹配的值道具。

例子:

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>

您可以根据自己的需要进行简单或复杂的切换。不要忘记对子节点及其值道具执行更健壮的检查。

试试这个,它也更干净:在一个函数中获得渲染的开关,并调用它传递你想要的参数。例如:

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