惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
IT之家
IT之家
H
Help Net Security
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
V
V2EX
M
MIT News - Artificial intelligence
Vercel News
Vercel News
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
阮一峰的网络日志
阮一峰的网络日志
B
Blog RSS Feed
D
Docker
V
Visual Studio Blog
博客园 - 叶小钗
美团技术团队
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
如何在 react 中使用 if-elseif-else 多重条件判断-蚊子的前...
author · 2020-08-28 · via 蚊子的前端博客

使用过 Vue 的同学们都知道,在 Vue 中有v-if, v-elseifv-else的语法糖,方便我们进行流程控制。但 react 中使用的 jsx,并没有这些语法糖,而是使用一些其他方式来实现条件控制的。

1. react 中的条件渲染 #

在 react 中有多种实现条件渲染的方式,我们每个稍微介绍一下。

1.1 与运算符&& #

当前面的表达式为真时,则执行后面的表达式。相当于if

// 当showModal变量为真时,则渲染弹窗,否则不显示
<div>{showModal && <Modal></Modal>}</div>

这里需要注意的是,当使用长度来控制的时候,要使用判断表达式,而不是直接用.length来判断,

// 要判断length>0,若只用list.length判断时,最后会渲染出来一个0
<div>{list.length > 0 && <Modal></Modal>}</div>

1.2 三目运算 #

当需要非黑即白时,这里就用到了三目运算。相当于if-else

<div>
  {list.length>0 ? `您一共有${list..length}条数据` : '您暂时还没有数据'}
</div>

1.3 立即执行或者单独的方法渲染 #

当需要更复杂的判断时,例如 3 个及以上的情况,或者多个判断条件时,即if-elseif-else的类型时,情况就稍微复杂一些。不过我们依然也有多种方式来实现。

  1. 多个嵌套的三目运算;
  2. 立即执行方法;
  3. 单独的方法;

1.3.1 多个嵌套的三目运算 #

嵌套的三目运算,也能作为多个 if 判断,但看起来实现逻辑有点乱:

const Home = () => {
  return <div>{A ? <>a right</> : B ? <>b right</> : <>else</>}</div>;
};

1.3.2 立即执行 #

const Home = () => {
  return (<div>
    {
      (() => {
        if (A) {
          return <>a right</>
        }
        if (B) {
          return <>b right</>
        }
        return <>else</>
      })();
    }
  </div>);
}

1.3.3 单独的方法 #

const Home = () => {
  const projectStatus = 1;
  const renderItem = (item) => {
    if (projectStatus !== 1) {
      return <button>活动暂未开始或已结束</button>;
    }
    if (item.status === 1) {
      return <button>点击参与</button>;
    }
    return <button>已无库存</button>;
  };

  return <div>{list.map((item) => renderItem(item))}</div>;
};

立即执行方法和单独的方法,都把判断逻辑进行了割裂。如果我依然想在 render 中的 jsx 中,写判断怎么办呢?

2. 新的方式 #

这里我一直想着用 Vue 中的方式一样,无需将条件判断独立出来,而是直接在顺着整体的思路往下写。这里我就封装了一个if-elseif-else的组件。

2.1 调用方式 #

先看下使用方式,然后再看代码实现。

import { When, Case } from './when';

const Home = () => {
  return (
    <div className="btn-container">
      <When>
        <Case if={status === 0 || status === 2}>
          <Button className="donate-btn-common cant-donate-hotvalue">
            {status === 0 ? '活动还未开始' : '活动已结束'}
          </Button>
        </Case>
        <Case elseif={projectState.process >= 100}>
          <Button className="donate-btn-common cant-donate-hotvalue">该项目已捐满</Button>
        </Case>
        <Case else>
          <Button loading={btnLoading} className="donate-btn-common donate-hotvalue" onClick={handleDonateClick}>
            捐热力值帮助TA
          </Button>
        </Case>
      </When>
    </div>
  );
};

这里用When进行包装,然后每个Case对应 1 个判断条件,从上往下,若某个为真,则直接渲染 children 中的内容,否则接着往下判断,直到最后。

这样实现起来,流程也比较顺,然后条件判断也很清晰。

2.2 代码实现 #

我们在这里直接贴代码,看看是怎么实现的:

import React from 'react';

const isArray = (arg: any): boolean => {
  if (Array.isArray) {
    return Array.isArray(arg);
  }
  return Object.prototype.toString.call(arg) === '[object Array]';
};

interface CaseProps {
  if?: boolean;
  elseif?: boolean;
  else?: boolean;
  children: JSX.Element | JSX.Element[];
}

export const Case = (props: CaseProps) => {
  return <>{props.children}</>;
};

export const When = ({ children }: { children: any }): JSX.Element | null => {
  if (!children) {
    return null;
  }

  let schildren: any = [];
  if (isArray(children)) {
    // 当存在多个case节点时,children为数组
    schildren = children;
  } else {
    // 当只有一个case节点,children为object类型
    schildren.push(children);
  }
  // 判断所有的子节点是不是Case类型
  schildren.forEach((child: any) => {
    if (!child.type || child.type.name !== Case.name) {
      throw new Error('the children of component When muse be component Case');
    }
  });
  // 查找if的节点,若有则直接返回
  const ifChildren = schildren.filter((item: any) => item.props.if);
  if (ifChildren.length) {
    return <>{ifChildren}</>;
  }
  // 再查找elseif的节点
  const elseIfChildren = schildren.filter((item: any) => item.props.elseif);
  if (elseIfChildren.length) {
    // 这里只输出第1个为true的组件
    return <>{elseIfChildren[0]}</>;
  }
  // 返回其他的节点
  return <>{schildren.filter((item: any) => item.props.else)}</>;
};

最终实现起来也非常的简单,按照顺序查找相应的属性,然后进行返回即可。

3. 总结 #

在 react 中,条件判断的方式有很多,官方的文档就介绍了很多种,但要实现一些稍微复杂点的条件判断时,就会让代码显得很凌乱。这里我也就实现实现了一套多重判断的机制。

机制如我