我有一个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?


当前回答

这个助手应该可以做到这一点。 使用示例:

{componentSwitch(3, (switcher => switcher
    .case(1, () =>
        <p>It is one</p>
    )
    .case(2, () =>
        <p>It is two</p>
    )
    .default(() =>
        <p>It is something different</p>
    )
))}

助手:

interface SwitchCases<T> {
    case: (value: T, result: () => React.ReactNode) => SwitchCases<T>;
    default: (result: () => React.ReactNode) => SwitchCases<T>;
}

export function componentSwitch<T>(value: T, cases: (cases: SwitchCases<T>) => void) {

    var possibleCases: { value: T, result: () => React.ReactNode }[] = [];
    var defaultResult: (() => React.ReactNode) | null = null;

    var getSwitchCases: () => SwitchCases<T> = () => ({
        case: (value: T, result: () => React.ReactNode) => {
            possibleCases.push({ value: value, result });

            return getSwitchCases();
        },
        default: (result: () => React.ReactNode) => {
            defaultResult = result;

            return getSwitchCases();
        },
    })
    
    // getSwitchCases is recursive and will add all possible cases to the possibleCases array and sets defaultResult.
    cases(getSwitchCases());

    // Check if one of the cases is met
    for(const possibleCase of possibleCases) {
        if (possibleCase.value === value) {
            return possibleCase.result();
        }
    }

    // Check if the default case is defined
    if (defaultResult) {
        // Typescript wrongly assumes that defaultResult is always null.
        var fixedDefaultResult = defaultResult as (() => React.ReactNode);

        return fixedDefaultResult();
    }

    // None of the cases were met and default was not defined.
    return undefined;
}

其他回答

与其他答案相比,我更倾向于在渲染函数中内联“开关”。它使什么组件可以在那个位置呈现更清楚。你可以使用一个简单的javascript对象来实现一个类似switch的表达式:

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

如何:

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

这是因为switch语句是一个语句,但这里javascript需要一个表达式。

虽然,不建议在呈现方法中使用switch语句,但你可以使用自调用函数来实现这一点:

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

改进了一点 马特·韦的回答。

export const Switch = ({ test, children }) => { const defaultResult = children.find((child) => child.props.default) || null; const result = children.find((child) => child.props.value === test); return result || defaultResult; }; export const Case = ({ children }) => children; const color = getColorFromTheMostComplexFnEver(); <Switch test={color}> <Case value="Green">Forest</Case> <Case value="Red">Blood</Case> <Case default>Predator</Case> </Switch> <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>

让它变得简单,只需使用许多if语句。

例如:

<Grid>
   {yourVar==="val1"&&(<> your code for val1 </>)}
   {yourVar==="val2"&&(<> your code for val2 </>)}
   .... other statments
</Grid>