如何在 React 组件中使用 switch 语句?
Posted
技术标签:
【中文标题】如何在 React 组件中使用 switch 语句?【英文标题】:How to use switch statement inside a React component? 【发布时间】:2018-03-17 11:57:36 【问题描述】:我有一个 React 组件,在组件的 render
方法中我有这样的东西:
render()
return (
<div>
<div>
// removed for brevity
</div>
switch(...)
<div>
// removed for brevity
</div>
</div>
);
现在的重点是我有两个div
元素,一个在顶部,一个在底部,它们是固定的。在中间我想要一个 switch 语句,并根据我的状态中的一个值,我想渲染一个不同的组件。所以基本上,我希望两个 div
元素始终被固定,并且每次都在中间渲染一个不同的组件。我正在使用它来实施多步骤付款程序)。不过,就像目前的代码一样,它不起作用,因为它给了我一个错误,说switch
是意外的。有什么想法可以实现我想要的吗?
【问题讨论】:
好吧,您不需要在return
语句甚至render
方法中包含所有这些逻辑。您能否将每个<div>
定义为一个常量,然后使用switch
before 你的return
来确定应该呈现哪个<div>
?
@JaredGoguen 但是,我需要在顶部和底部重复 div
,对于 switch
的每种情况多次重复。或者我只是误会了,你..
不,您可以为let middleDiv = ...
创建代码,然后将middleDiv
包含在您在那里硬编码的两个<div>
s 之间的返回JSX 中。
【参考方案1】:
我正在使用这个助手,它允许我在 JSX 中使用 switch 语句
// in helpers folder
const switchTrue = (object) =>
const default: defaultValue, ...rest = object;
const obj = default: defaultValue, ...rest ;
const result = Object.keys(obj).reduce((acc, cur) =>
return
...acc,
[cur === 'default' ? 'true' : cur]: obj[cur],
;
, );
return result['true'];
;
const Sample = () =>
const isDataLoading = false;
return (
<div>
switchTrue(
[`$isDataLoading`]: <div>Loading</div>,
[`$!isDataLoading`]: <div>Data Ready</div>,
default: <div>Default</div>,
)
</div>
)
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>
【讨论】:
【参考方案2】:虽然这是另一种实现方式,但如果您已经全押,您可以利用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
函数使用闭包来访问传入组件的必要道具。一个单独的函数(如接受的答案)需要将 props 传递给它,这可能很麻烦(尤其是在使用 TypeScript 时,因为参数也应该正确输入)
【讨论】:
【参考方案3】:import React from 'react';
import ListView from './ListView';
import TableView from './TableView';
function DataView(
currView,
data,
onSelect,
onChangeStatus,
viewTodo,
editTodo,
deleteTodo,
)
return (
<div>
(function ()
switch (currView)
case 'table':
return (
<TableView
todos=data
onSelect=onSelect
onChangeStatus=onChangeStatus
viewTodo=viewTodo
editTodo=editTodo
deleteTodo=deleteTodo
/>
);
case 'list':
return (
<ListView
todos=data
onSelect=onSelect
onChangeStatus=onChangeStatus
viewTodo=viewTodo
editTodo=editTodo
deleteTodo=deleteTodo
/>
);
default:
break;
)()
</div>
);
export default DataView;
【讨论】:
【参考方案4】:让它变得简单,只需使用许多 if 语句。
例如:
<Grid>
yourVar==="val1"&&(<> your code for val1 </>)
yourVar==="val2"&&(<> your code for val2 </>)
.... other statments
</Grid>
【讨论】:
【参考方案5】:试试这个,它也更简洁:在函数中将该开关从渲染中取出,然后通过传递您想要的参数调用它。例如:
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>
);
【讨论】:
如果你把函数调用放在返回中,它总是调用渲染。因此,如果您需要从 return 语句以外的其他地方调用 renderSwitch,这是行不通的。 此外,它被多次调用。【参考方案6】:我知道我参加聚会有点晚了,但我认为这个实施可能会有所帮助
您可以使用条件运算符来渲染组件
如果你有以下 switch 语句
switch(value)
case CASE1:
return <Case1Component/>
case CASE2:
return <Case2Component/>
case CASE3:
return <Case3Component/>
default:
return <DefaultComponent/>
你可以把它转换成这样的反应组件
const cases = [CASE0, CASE1, CASE2]
// Reminds me of 'react-router-dom'
return (
<div>
value === cases[0] && <Case0Component/>
value === cases[1] && <Case1Component/>
value === cases[2] && <Case2Component/>
!cases.includes(value) && <DefaultComponent/>
</div>
)
【讨论】:
【参考方案7】:React Component 中的 Switch-Case 语句可以如下使用:
<div id="time-list">
(() =>
switch (groupByFilterId)
case 0:/*Case 0 */
return (
<div>Case 0</div>
)
break;
case 1: /*Case 1 */
return (
<div>Case 1</div>
)
break;
case 2:/*Case 2 */
return (
<div>Case 2</div>
)
break;
)()
</div>
【讨论】:
复制我的答案【参考方案8】:此答案专门针对@tonyfat 撰写的this "duplicate" question,关于如何使用条件表达式来处理相同的任务。
在这里避免声明似乎比它的价值更麻烦,但这个脚本完成了 sn-p 演示的工作:
// 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)`)
【讨论】:
我同意这是一个更好更简洁的语法,如果命名/约定不是很清楚,你也可以使用 cmets。 最不清晰的选项【参考方案9】:我将接受的答案转换为箭头功能组件解决方案,并看到 James 提供了类似的答案,并且可能会收到错误 not defined
。所以这里是解决方案:
const renderSwitch = (param) =>
switch (param)
case "foo":
return "bar";
default:
return "foo";
;
return (
<div>
<div></div>
renderSwitch(param)
<div></div>
</div>
);
【讨论】:
【参考方案10】:
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>
);
【讨论】:
【参考方案11】:我不是当前任何答案的忠实粉丝,因为它们要么过于冗长,要么需要您跳过代码才能了解发生了什么。
我更喜欢通过创建<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>
您可以根据需要使切换变得简单或复杂。不要忘记对孩子及其价值道具执行更稳健的检查。
【讨论】:
正是我想要的!这里有一点改进: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>
虽然这是一个很好的解决方案,但在代码中添加解释会更好
@papigee 更新了一些细节。
@MattWay 虽然这对于纯 JS 来说是一个不错的选择,但当目标设置为 es5 时会引发 TS 错误,因为 ReactNode 上不存在属性查找
***.com/a/63852247/733092 的 TypeScript 版本。【参考方案12】:
我真的很喜欢 https://***.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>;
【讨论】:
太棒了。现在在***.com/questions/46592833/… 中添加<Case />
并将其发布为npm 包:-)【参考方案13】:
一种在渲染块中表示一种开关的方法,使用条件运算符:
(someVar === 1 &&
<SomeContent/>)
|| (someVar === 2 &&
<SomeOtherContent />)
|| (this.props.someProp === "something" &&
<YetSomeOtherContent />)
|| (this.props.someProp === "foo" && this.props.someOtherProp === "bar" &&
<OtherContentAgain />)
||
<SomeDefaultContent />
应确保条件严格返回布尔值。
【讨论】:
漂亮优雅,可以直接在渲染块中使用。最佳答案恕我直言 我注意到这违反了 EsLints 规则 eslint.org/docs/rules/no-mixed-operators 混合 && 和 || @FishFingers 当我尝试完全按照上述方式使用它时,我也注意到了这一点。通过将每个“案例”括在括号中可以很容易地避免这种情况。 与普通开关相比,这有什么好处吗? Switch 更干净,很容易看到什么去哪里,这对于做同样的事情 IMO 来说是相当复杂的。下一个 && 然后 || 在哪里,如果 OR 这个 AND 那会发生什么.. @James 这是一种方法,其思想状态以及因此的好处与 React 文档中提到的“带有条件运算符的内联 If”相同:reactjs.org/docs/…。我什至会说它只是它的延伸。喜欢将一些渲染逻辑从渲染块中分离出来是一种主观的选择,而对条件运算符的熟练程度则是个人的事情。【参考方案14】:这是一个使用按钮在组件之间切换的完整示例
你可以设置如下构造函数
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>
);
如您所见,我正在使用一个按钮在状态之间切换。
【讨论】:
【参考方案15】:这是另一种方法。
render()
return this[`renderStep$this.state.step`]()
renderStep0() return 'step 0'
renderStep1() return 'step 1'
【讨论】:
【参考方案16】:渲染中不能有开关。放置访问一个元素的对象文字的伪开关方法并不理想,因为它会导致所有视图都被处理,并且可能导致该状态下不存在的道具的依赖错误。
这是一种非常简洁的方法,不需要提前渲染每个视图:
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>
)
如果视图状态的条件不仅仅基于一个简单的属性——比如每行多个条件,那么一个枚举和一个 getViewState
函数来封装条件是分离这个条件逻辑并清理你的渲染。
【讨论】:
简单干净的方式。【参考方案17】: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
【讨论】:
key1:我在 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_dev 我们可以将它作为组件方法放置在 render 方法中,而不是 'const project' 函数,然后在 render return 中调用它,如 " this.project() ”。除非您说根本不使用 switch,否则我可以考虑使用 if/else,或者通过更新状态使用 className 显示/隐藏组件。 这可能会更好,因为例如我使用路由组件的head()
方法将react-helmet
的数据注入到我的文档头部
我将此解决方案与功能组件一起使用,并且可以正常工作。干得好。【参考方案19】:
与其他答案相比,我更愿意在渲染函数中内联“开关”。它使在该位置可以渲染哪些组件更加清晰。您可以使用普通的旧 javascript 对象来实现类似 switch 的表达式:
render ()
return (
<div>
<div>
/* removed for brevity */
</div>
'foo': <Foo />,
'bar': <Bar />
[param]
<div>
/* removed for brevity */
</div>
</div>
)
【讨论】:
这很酷。我稍微修改了它以使用数组而不是 POJO,我只是使用索引将括号括入数组中。 这是在 Python 中处理 switch-case 的标准方法。在这种情况下,我更喜欢它,因为它具有出色的可读性。 这种方法有其局限性和开销。您的每个视图都将被处理,并将取决于可能不存在的当前状态/道具。例如:假设您想渲染:<SearchResults />
或 <NoResults />
。如果视图状态应该呈现<NoResults />
,<SearchResults />
可能无法编译,因为它依赖于尚不存在的属性。
默认情况如何?
@lama12345 默认情况下,使用||
,如下: 'foo': <Foo />, 'bar': <Bar /> [param] || <Baz />
【参考方案20】:
怎么样:
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>
);
【讨论】:
【参考方案21】:发生这种情况,因为 switch
语句是 statement
,但这里的 javascript 需要一个表达式。
虽然不建议在render
方法中使用switch语句,但可以使用自调用函数来实现:
render()
// Don't forget to return a value in a switch statement
return (
<div>
(() =>
switch(...)
)()
</div>
);
【讨论】:
谢谢我用过这样的:render () return ( (() => switch (this.state.type) case commons.HARD_SOFT: return你可以这样做。
<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 />
【讨论】:
以上是关于如何在 React 组件中使用 switch 语句?的主要内容,如果未能解决你的问题,请参考以下文章
react-router-dom 中的 Switch 语句始终加载 Home 路由,没有其他路由
如何在 React Native 中使用 switch 进行条件渲染?
React 项目使用 switch ... case ... 语句