在 React 中使用条件渲染并不困难。在 JSX 中——用于 React 的语法扩展——您可以使用纯 JavaScript,其中包括 if else 语句、三元操作符、 switch case 语句等等。在条件渲染中,React 组件根据一个或多个条件决定将返回哪些 DOM 元素。 例如,基于某种逻辑,它可以返回一个项目列表或者一个文本,上面写着“对不起,列表是空的”。当组件具有条件渲染时,渲染的组件外观根据条件不同而不同。本文旨在为 React 中的条件渲染和这些模式的最佳实践提供一个详尽的选择清单。
目录
- React条件渲染:if
- React条件渲染:if else
- React条件渲染:三元
- React条件渲染:&&
- React条件渲染:switch case
- React多条件渲染
- React嵌套条件渲染
- 使用HOC的条件渲染
- React中的if else组件
React条件渲染:if
React 中最基本的条件渲染逻辑是用一个 if 语句完成的。假设您不想在 React 组件中渲染某些内容,因为它没有必要的 React props 可用。 例如,如果开始没有list的话,React 中的 List 组件不应该在视图中渲染list的HTML元素。 你可以使用一个简单的 JavaScript if 语句提前返回(守卫模式) :
const users = [
{ id: '1', firstName: 'Robin', lastName: 'Wieruch' },
{ id: '2', firstName: 'Dennis', lastName: 'Wieruch' },
];
function App() {
return (
<div>
<h1>Hello Conditional Rendering</h1>
<List list={users} />
</div>
);
}
function List({ list }) {
if (!list) {
return null;
}
return (
<ul>
{list.map(item => (
<Item key={item.id} item={item} />
))}
</ul>
);
}
function Item({ item }) {
return (
<li>
{item.firstName} {item.lastName}
</li>
);
}
您可以自己尝试将用户设置为 null 或 undefined。 如果props中的信息为 null 或 undefined,则 React 组件在条件渲染中返回 null。 在这里,返回 null 而不是 JSX 的 React 组件将不渲染任何内容。
在这个例子中,我们已经完成了基于 props 的条件渲染,但是条件渲染也可以基于 state 和 hooks 。 注意,我们还没有在 JSX 内部使用 if 语句,而只是在 return 语句之前在外部使用 if 语句。
React条件渲染:if else
让我们继续前面的例子来学习 React 中的 if else 语句。 如果没有list,我们就不渲染任何内容,并隐藏 HTML,就像我们之前用单个 if 语句所看到的那样。 但是,为了获得更好的用户体验,当list为空时,您可能希望为用户显示一个文本作为反馈。 这将与另一个 if 语句一起使用,但是我们将用 if else 语句扩展这个例子:
function List({ list }) {
if (!list) {
return null;
}
if (!list.length) {
return <p>Sorry, the list is empty.</p>;
} else {
return (
<div>
{list.map(item => (
<Item item={item} />
))}
</div>
);
}
}
现在,List 组件根据一些 JavaScript 逻辑不渲染任何内容、文本或列表。尽管前面的例子展示了如何在 React 中使用 if else 语句,我还是建议在每次需要保护主返回内容时使用单个 if 语句(这里: 返回列表)作为最佳实践:
function List({ list }) {
if (!list) {
return null;
}
if (!list.length) {
return <p>Sorry, the list is empty.</p>;
}
return (
<div>
{list.map(item => (
<Item item={item} />
))}
</div>
);
}
这比之前的 if else 条件渲染更具可读性。 所有守卫整齐地排列为主返回语句之前的 if 语句,这也可以解释为隐含的 else 语句。 尽管如此,在 return 语句中还没有使用 if 和 else 语句。
React条件渲染:三元
的确,我们可以在 JSX 中使用 JavaScript,但是在 JSX 中使用 if,else,switch case 这样的语句会变得很困难。 没有真正的方法来内联它。 在 JavaScript 中表达 if else 语句的另一种方式是三元运算符:
// if else
function getFood(isVegetarian) {
if (isVegetarian) {
return 'tofu';
} else {
return 'fish';
}
}
// ternary operator
function getFood(isVegetarian) {
return isVegetarian ? 'tofu' : 'fish';
}
例如,假设您的组件显示预览或编辑模式。 条件是一个 JavaScript 布尔值,以 React prop 的形式出现。 你可以使用布尔值来决定你想要条件渲染哪个元素:
function Recipe({ food, isEdit }) {
return (
<div>
{food.name}
{isEdit ? (
<EditRecipe food={food} />
) : (
<ShowRecipe food={food} />
)}
</div>
);
}
三元操作符中两个隐式 return 语句周围的括号()使您能够返回单个或多个 HTML 元素,或从那里返回 React 组件。 如果只有一个元素,可以省略括号。
注意: 有时候你需要用一个 div 元素包裹多行元素作为一个块。 不管怎样,尽量保持轻量化。 如果()之间包裹的内容太大,可以考虑将其作为组件提取,如示例中所示。
在 React 中使用三元运算渲染不仅使条件渲染更加简洁,而且为你在返回中内嵌条件渲染提供了一种简单的方法。 这样,只有一部分 JSX 是有条件地渲染的,而其他部分可以不受任何条件限制地保持完整。
React条件渲染:&&
这种情况经常发生,你想要渲染一个元素或者什么都不渲染。 你已经知道一个简单的if条件可以帮助解决这个问题。 但是,您还是希望能够像三元运算符那样内联条件。 使用下面的加载指示符组件,它使用条件三元操作符返回元素或者什么都不返回:
function LoadingIndicator({ isLoading }) {
return <div>{isLoading ? <p>Loading...</p> : null}</div>;
}
这个完成的不错,你在你的 JSX 内联了条件。 然而,还有一种替代方法可以省略返回 null 的必要性。
逻辑 && 运算符可以帮助您使返回 null 的条件更简洁。 在 JavaScript 中,一个 true && Hello World 总是等于 Hello World。 False && Hello World 总是被计算为 false:
const result = true && 'Hello World';
console.log(result);
// Hello World
const result = false && 'Hello World';
console.log(result);
// false
在React中,你可以利用这种行为。 如果条件为真,逻辑 && 运算符后面的表达式将作为输出。 如果条件为 false,React 忽略并跳过表达式:
function LoadingIndicator({ isLoading }) {
return <div>{isLoading && <p>Loading...</p>}</div>;
}
当您希望不返回任何内容或 JSX 中的元素时,这是您的方式。 它也被称为短路求值,这使得它甚至比三元操作符更简洁。
React条件渲染:switch case
现在可能会出现多个条件渲染的情况。 例如,通知组件基于状态字符串渲染错误、警告或信息组件:
function Notification({ text, status }) {
if (status === 'info') {
return <Info text={text} />;
}
if (status === 'warning') {
return <Warning text={text} />;
}
if (status === 'error') {
return <Error text={text} />;
}
return null;
}
您可以使用 switch case 操作符来处理多个条件渲染:
function Notification({ text, status }) {
switch (status) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'error':
return <Error text={text} />;
default:
return null;
}
}
对 switch case 操作符使用 default 是明智的,因为 React 组件总是必须返回一个元素或 null。 如果一个组件有一个基于字符串的条件渲染,那么用 TypeScript 来描述组件的接口是有意义的:
type Status = 'info' | 'warning' | 'error';
type NotificationProps = {
text: string;
status: Status;
};
function Notification({ text, status }: NotificationProps) {
switch (status) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'error':
return <Error text={text} />;
default:
return null;
}
}
对于多个条件渲染来说,switch case 写是一个很好的开始。 但是它也有同样的缺点,就像 if else 语句一样。 不能在 JSX 中使用 switch case,对吧? 实际上它可以通过一个条件渲染函数来实现,这个函数是自调用的:
function Notification({ text, status }) {
return (
<div>
{(function() {
switch (status) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'error':
return <Error text={text} />;
default:
return null;
}
})()}
</div>
);
}
可以选择使用条件渲染箭头函数使 switch case 更简洁:
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>
);
}
总之,switch case 操作符可以帮助您实现多个条件渲染。 但是这是最好的方法吗? 让我们看看如何用枚举来代替多个条件渲染。
React多条件渲染
带有映射关系的键值对的 JavaScript 对象称为枚举:
const NOTIFICATION_STATES = {
info: 'Did you know? ...',
warning: 'Be careful here ...',
error: 'Something went wrong ...',
};
枚举是处理 React 中带有多个条件的条件渲染的一种很好的方法。 它们比 switch case 语句更给力,因为它们可以在 JSX 中使用。 让我们再次考虑通知组件,但这次使用枚举作为内联对象(内部花括号) :
function Notification({ text, status }) {
return (
<div>
{
{
info: <Info text={text} />,
warning: <Warning text={text} />,
error: <Error text={text} />,
}[status]
}
</div>
);
}
status 属性键帮助我们从对象中检索值。 很棒,不是吗? 与 switch case 写操作符相比,它更具可读性。
在本例中,我们必须使用内联对象,因为对象的值依赖于 text 属性。 无论如何,这是我推荐的方式。 但是,如果它不依赖于 text 属性,你可以使用一个枚举作为条件渲染的常量:
const NOTIFICATION_STATES = {
info: <Info />,
warning: <Warning />,
error: <Error />,
};
function Notification({ status }) {
return (
<div>
{NOTIFICATION_STATES[status]}
</div>
);
}
这样事情就解决了。 如果我们仍然依赖之前的 text 属性,我们可以使用一个带有函数的条件渲染来检索值:
const getNotification = text => ({
info: <Info text={text} />,
warning: <Warning text={text} />,
error: <Error text={text} />,
});
function Notification({ status, text }) {
return <div>{getNotification(text)[status]}</div>;
}
毕竟,React 中的枚举条件渲染比 switch case 语句更优雅。 作为枚举的对象提供了大量的选项来实现多个条件渲染。 布尔型的排列也是可能的:
function Message({ isExtrovert, isVegetarian }) {
const key = `${isExtrovert}-${isVegetarian}`;
return (
<div>
{
{
'true-true': <p>I am an extroverted vegetarian.</p>,
'true-false': <p>I am an extroverted meat eater.</p>,
'false-true': <p>I am an introverted vegetarian.</p>,
'false-false': <p>I am an introverted meat eater.</p>,
}[key]
}
</div>
);
}
最后一个例子有点过头了,我不建议使用它。 然而,当涉及到条件渲染,枚举是我最喜欢的一个React模式。
React嵌套条件渲染
那么在 React 中嵌套条件渲染呢? 是的,这是可能的。 例如,让我们看看之前的 List 组件,它显示了一个列表、一个空文本或者什么都没有:
function List({ list }) {
const isNotAvailable = !list;
const isEmpty = !list.length;
return (
<div>
{isNotAvailable
? <p>Sorry, the list is not there.</p>
: (isEmpty
? <p>Sorry, the list is empty.</p>
: <div>{list.map(item => <Item item={item} />)}</div>
)
}
</div>
);
}
它可以工作,但我建议避免嵌套条件渲染,因为他们是冗长的,这使得它不太可读。 试试下面的解决方案:
- 仅在主返回语句之前使用 if 语句的守卫模式
- 将组件拆分为多个组件,而每个组件负责自己的非嵌套条件渲染
使用HOC的条件渲染
高阶组件(Higher-Order Components,HOCs)是 React 中条件渲染的完美匹配。 Hoc 可以帮助处理多个使用场景,但是一个场景可能是使用条件渲染来改变组件的外观。 让我们看看一个显示元素或组件的 HOC:
// Higher-Order Component
function withLoadingIndicator(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
if (!isLoading) {
return <Component {...props} />;
}
return (
<div>
<p>Loading</p>
</div>
);
};
}
const ListWithLoadingIndicator = withLoadingIndicator(List);
function App({ list, isLoading }) {
return (
<div>
<h1>Hello Conditional Rendering</h1>
<ListWithLoadingIndicator isLoading={isLoading} list={list} />
</div>
);
}
在这个示例中,List 组件可以专注于渲染列表。 它不必担心加载状态。 一个 HOC 在您的实际组件中隐藏了所有的噪音。 最终,您可以添加多个高阶组件(组合) ,以隐藏多个条件渲染边缘情况。 作为 hoc 的替代品,你也可以使用 render prop 支持条件渲染。
React中的if else组件
最后但并非最不重要的是,有外部库处理标记级别上的条件渲染。 他们添加了控制组件,以便在没有 JS 的情况下启用条件渲染:
<Choose>
<When condition={isLoading}>
<div><p>Loading...</p></div>
</When>
<Otherwise>
<div>{list.map(item => <Item item={item} />)}</div>
</Otherwise>
</Choose>
很多人认为React(包括JSX)是他们的首选库,因为他们可以在JSX中使用纯HTML和JS处理渲染。
我希望这个 React 教程对您学习条件渲染有所帮助。 如果你喜欢它,请与你的朋友分享。 最后,我为你准备了一个全部条件渲染的备忘单:
- if
- 最基本的条件渲染
- 用于在一个渲染中提前返回(守卫模式)
- 不能在 return 语句和 JSX 中使用(自调用函数除外)
- if-else
- 很少用它,因为它太冗长了
- 可以使用三元运算符或逻辑 && 运算符替代
- 不能在 return 语句和 JSX 中使用(自调用函数除外)
- 三元运算符
- 用它代替 if-else 语句
- 它可以在 JSX 和 return 语句中使用
- 逻辑 && 操作符
- 当三元运算的一端返回 null 时使用它
- 它可以在 JSX 和 return 语句中使用
- switch case
- 避免使用它,因为它太冗长
- 可以用枚举替代
- 不能在 return 语句和 JSX 中使用(自调用函数除外)
- 枚举
- 使用它来进行基于多个状态的条件渲染
- 完美地映射多个条件
- 嵌套条件渲染
- 为了可读性,避免使用它们
- 可以拆分组件、使用 if 语句或者使用 hoc 替代
- HOCs(高阶组件)
- 组件可以专注于它们的主要目的
- 使用 HOC 屏蔽条件渲染
- 使用多个可组合 hoc 屏蔽多个条件渲染
- 外部模板组件
- 避免使用它们,并适应 JSX 和 JS