MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

React 条件渲染基础入门

2023-01-216.8k 阅读

什么是 React 条件渲染

在 React 应用开发中,条件渲染是一种根据特定条件来决定是否渲染或如何渲染 UI 组件的技术。它允许我们根据应用的状态或其他条件动态地展示不同的用户界面。这在实际应用中非常常见,比如根据用户是否登录来显示不同的导航栏,或者根据数据的存在与否来展示不同的提示信息等。

React 中的条件渲染本质上是利用 JavaScript 的条件语句,如 if - else 、三元运算符 ? : 以及逻辑与运算符 && 来控制组件的渲染。与传统 HTML 模板不同,React 条件渲染将条件逻辑与 UI 渲染紧密结合,这使得代码更具可读性和维护性,同时也符合 React 基于组件构建 UI 的理念。

使用 if 语句进行条件渲染

基本的 if 语句

在 React 组件中,最直接的方式就是使用 JavaScript 的 if 语句来进行条件渲染。假设我们有一个简单的组件,根据某个布尔值来决定是否显示一段文本。

import React from 'react';

function Greeting() {
    const isLoggedIn = true;
    let message;
    if (isLoggedIn) {
        message = <p>欢迎回来!</p>;
    } else {
        message = <p>请登录。</p>;
    }
    return (
        <div>
            {message}
        </div>
    );
}

export default Greeting;

在上述代码中,我们定义了一个 Greeting 组件,通过 isLoggedIn 这个布尔值来决定 message 的内容。然后在 return 语句中,将 message 嵌入到 JSX 中进行渲染。这里要注意,message 是一个 JSX 元素,而不是字符串,这是 React 条件渲染的一个重要特点。

在函数中使用 if 语句进行多条件渲染

如果有多个条件需要判断,我们可以在函数中嵌套 if 语句。例如,我们根据用户的角色来显示不同的内容。

import React from 'react';

function UserRoleComponent() {
    const userRole = 'admin';
    let content;
    if (userRole === 'admin') {
        content = <p>您是管理员,拥有所有权限。</p>;
    } else if (userRole === 'editor') {
        content = <p>您是编辑,可以修改内容。</p>;
    } else {
        content = <p>您是普通用户,只能查看。</p>;
    }
    return (
        <div>
            {content}
        </div>
    );
}

export default UserRoleComponent;

上述代码展示了如何根据不同的 userRole 值来显示不同的文本。这种方式适用于条件较为复杂且需要多个分支判断的情况。

在 React 组件生命周期方法中使用 if 语句

在 React 组件的生命周期方法中,if 语句也常用于条件渲染。比如在 componentDidMount 方法中,根据某个条件来决定是否发起网络请求。

import React, { Component } from'react';

class DataFetcher extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: null,
            shouldFetch: true
        };
    }

    componentDidMount() {
        if (this.state.shouldFetch) {
            // 模拟网络请求
            setTimeout(() => {
                this.setState({
                    data: '从服务器获取的数据'
                });
            }, 1000);
        }
    }

    render() {
        let displayContent;
        if (this.state.data) {
            displayContent = <p>{this.state.data}</p>;
        } else {
            displayContent = <p>数据正在加载或未获取。</p>;
        }
        return (
            <div>
                {displayContent}
            </div>
        );
    }
}

export default DataFetcher;

在这个例子中,componentDidMount 方法里的 if 语句决定是否发起模拟的网络请求。而在 render 方法中,if 语句根据 state 中的数据是否存在来决定显示不同的内容。

使用三元运算符进行条件渲染

简单的三元运算符使用

三元运算符 condition? expression1 : expression2 是 JavaScript 中一种简洁的条件判断方式,在 React 中也经常用于条件渲染。它可以使代码更加紧凑。

import React from'react';

function LoginStatus() {
    const isLoggedIn = false;
    return (
        <div>
            {isLoggedIn? <p>已登录</p> : <p>未登录</p>}
        </div>
    );
}

export default LoginStatus;

在上述代码中,isLoggedIn 作为条件,当为 true 时,显示 “已登录”;为 false 时,显示 “未登录”。这种方式在简单条件判断时非常方便,使得代码更具可读性和简洁性。

嵌套三元运算符实现复杂条件

当有多个条件需要判断时,我们可以嵌套三元运算符。例如,根据用户的年龄和会员状态来显示不同的消息。

import React from'react';

function UserMessage() {
    const age = 25;
    const isMember = true;
    return (
        <div>
            {age >= 18? (
                isMember? <p>欢迎成年会员!</p> : <p>欢迎成年非会员!</p>
            ) : (
                <p>未满 18 岁,暂不提供服务。</p>
            )}
        </div>
    );
}

export default UserMessage;

在这个例子中,首先判断用户年龄是否大于等于 18 岁。如果是,再判断是否为会员,从而显示不同的消息。虽然嵌套三元运算符可以实现复杂条件,但过多的嵌套可能会使代码可读性下降,所以在使用时要权衡。

结合函数调用使用三元运算符

我们还可以在三元运算符中调用函数。比如,根据用户输入的数字,调用不同的格式化函数来显示结果。

import React, { useState } from'react';

function NumberFormatter() {
    const [number, setNumber] = useState(0);
    const formatPositive = num => `正数:${num}`;
    const formatNegative = num => `负数:${num}`;
    return (
        <div>
            <input
                type="number"
                value={number}
                onChange={e => setNumber(parseInt(e.target.value, 10))}
            />
            {number >= 0? formatPositive(number) : formatNegative(number)}
        </div>
    );
}

export default NumberFormatter;

在上述代码中,用户在输入框中输入数字,通过三元运算符根据数字的正负调用不同的格式化函数来显示结果。这种方式将条件判断和业务逻辑处理结合起来,使代码更加灵活。

使用逻辑与运算符 && 进行条件渲染

基本的 && 运算符条件渲染

逻辑与运算符 && 在 React 条件渲染中有独特的用途。它可以简洁地根据条件决定是否渲染某个组件。如果 && 左边的表达式为 true,则渲染右边的组件;如果为 false,则不会渲染右边的组件。

import React from'react';

function ShowMessage() {
    const show = true;
    return (
        <div>
            {show && <p>这是一条显示的消息。</p>}
        </div>
    );
}

export default ShowMessage;

在这个例子中,只有当 showtrue 时,<p>这是一条显示的消息。</p> 才会被渲染。如果 showfalse,则不会有任何内容渲染。

使用 && 运算符进行多个组件的条件渲染

我们可以在 && 后连接多个组件,只要前面的条件为 true,这些组件都会被渲染。

import React from'react';

function MultipleComponents() {
    const condition = true;
    return (
        <div>
            {condition && (
                <div>
                    <p>第一个组件</p>
                    <p>第二个组件</p>
                </div>
            )}
        </div>
    );
}

export default MultipleComponents;

在上述代码中,如果 conditiontrue,那么 <div> 内部的两个 <p> 组件都会被渲染。这里要注意,需要将多个组件用一个父元素包裹起来,否则会报错,因为 React 要求 && 后返回的是一个单一的元素或 null

结合函数调用使用 && 运算符

&& 运算符还可以结合函数调用。例如,当某个条件满足时,调用一个函数来处理数据并渲染结果。

import React, { useState } from'react';

function DataProcessor() {
    const [inputValue, setInputValue] = useState('');
    const processData = value => `处理后的数据:${value.toUpperCase()}`;
    return (
        <div>
            <input
                type="text"
                value={inputValue}
                onChange={e => setInputValue(e.target.value)}
            />
            {inputValue && <p>{processData(inputValue)}</p>}
        </div>
    );
}

export default DataProcessor;

在这个例子中,只有当 inputValue 有值时(即用户在输入框中输入了内容),才会调用 processData 函数并渲染处理后的数据。

条件渲染中的注意事项

避免空值渲染问题

在使用条件渲染时,要注意避免渲染空值。例如,当使用 && 运算符时,如果条件为 false,右边的表达式不应返回 undefined 或其他非 React 元素的值,否则可能会导致错误。

import React from'react';

function AvoidNullRender() {
    const condition = false;
    // 错误示例,右边返回了 undefined
    // const wrongRender = condition && undefined;
    // 正确示例,右边返回 null
    const correctRender = condition && null;
    return (
        <div>
            {correctRender}
        </div>
    );
}

export default AvoidNullRender;

在上述代码中,错误示例中右边返回 undefined 会导致问题,而正确示例返回 null 则不会有问题,因为 React 可以正确处理 null 的渲染。

条件改变时的重新渲染

当条件依赖的状态或属性发生变化时,React 会重新渲染组件并根据新的条件进行 UI 更新。但是,要注意不必要的重新渲染可能会影响性能。例如,如果一个组件在每次父组件渲染时都重新渲染,即使其条件未改变,这可能会造成性能浪费。可以通过 shouldComponentUpdate 方法(在类组件中)或 React.memo(在函数组件中)来优化。

import React, { Component } from'react';

class ConditionalRenderPerformance extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        // 这里只比较需要关注的条件相关的属性或状态
        return this.props.condition!== nextProps.condition;
    }

    render() {
        const { condition } = this.props;
        return (
            <div>
                {condition && <p>条件满足时显示。</p>}
            </div>
        );
    }
}

export default ConditionalRenderPerformance;

在上述类组件中,通过 shouldComponentUpdate 方法,只有当 condition 属性发生变化时,组件才会重新渲染,从而提高了性能。对于函数组件,可以使用 React.memo 来实现类似的功能。

import React from'react';

const ConditionalRenderPerformance = React.memo(({ condition }) => (
    <div>
        {condition && <p>条件满足时显示。</p>}
    </div>
));

export default ConditionalRenderPerformance;

React.memo 会浅比较组件的 props,如果 props 没有变化,组件就不会重新渲染。

条件渲染与样式处理

在条件渲染中,经常需要根据条件来应用不同的样式。可以通过动态生成 CSS 类名或使用内联样式来实现。

使用动态 CSS 类名

import React, { useState } from'react';
import './styles.css';

function ConditionalStyle() {
    const [isActive, setIsActive] = useState(false);
    const className = isActive? 'active' : 'inactive';
    return (
        <div className={className}>
            <button onClick={() => setIsActive(!isActive)}>
                {isActive? '取消激活' : '激活'}
            </button>
        </div>
    );
}

export default ConditionalStyle;

styles.css 文件中定义 activeinactive 两个类的样式。当 isActivetrue 时,应用 active 类的样式;为 false 时,应用 inactive 类的样式。

使用内联样式

import React, { useState } from'react';

function InlineConditionalStyle() {
    const [isHighlighted, setIsHighlighted] = useState(false);
    const style = {
        color: isHighlighted? 'blue' : 'black',
        fontWeight: isHighlighted? 'bold' : 'normal'
    };
    return (
        <div>
            <p style={style}>这是一段根据条件改变样式的文本。</p>
            <button onClick={() => setIsHighlighted(!isHighlighted)}>
                {isHighlighted? '取消高亮' : '高亮'}
            </button>
        </div>
    );
}

export default InlineConditionalStyle;

在上述代码中,通过 style 对象根据 isHighlighted 的值动态设置文本的颜色和字体粗细。

条件渲染在列表中的应用

根据条件过滤列表项

在 React 中,我们经常需要根据条件过滤列表项并进行渲染。例如,有一个任务列表,根据任务的完成状态来过滤显示。

import React from'react';

function TaskList() {
    const tasks = [
        { id: 1, text: '任务 1', completed: true },
        { id: 2, text: '任务 2', completed: false },
        { id: 3, text: '任务 3', completed: true }
    ];
    const showCompleted = true;
    const filteredTasks = showCompleted? tasks.filter(task => task.completed) : tasks.filter(task =>!task.completed);
    return (
        <ul>
            {filteredTasks.map(task => (
                <li key={task.id}>{task.text} - {task.completed? '已完成' : '未完成'}</li>
            ))}
        </ul>
    );
}

export default TaskList;

在上述代码中,通过 showCompleted 这个条件来决定是显示已完成的任务还是未完成的任务。使用 filter 方法对任务列表进行过滤,然后通过 map 方法进行渲染。

条件渲染列表项的样式

除了过滤列表项,还可以根据条件渲染列表项的不同样式。例如,对于已完成的任务,应用不同的文本颜色和装饰。

import React from'react';

function StyledTaskList() {
    const tasks = [
        { id: 1, text: '任务 1', completed: true },
        { id: 2, text: '任务 2', completed: false },
        { id: 3, text: '任务 3', completed: true }
    ];
    return (
        <ul>
            {tasks.map(task => {
                const style = {
                    textDecoration: task.completed? 'line - through' : 'none',
                    color: task.completed? 'gray' : 'black'
                };
                return (
                    <li key={task.id} style={style}>
                        {task.text} - {task.completed? '已完成' : '未完成'}
                    </li>
                );
            })}
        </ul>
    );
}

export default StyledTaskList;

在这个例子中,根据任务的 completed 状态,为每个列表项应用不同的文本装饰和颜色样式。

在列表中嵌套条件渲染

有时候,列表项内部还可能需要根据其他条件进行更复杂的条件渲染。比如,任务列表中,如果任务有子任务,根据子任务的状态来显示不同的图标。

import React from'react';

function NestedConditionalList() {
    const tasks = [
        {
            id: 1,
            text: '任务 1',
            completed: true,
            subTasks: [
                { id: 11, text: '子任务 11', completed: true },
                { id: 12, text: '子任务 12', completed: false }
            ]
        },
        { id: 2, text: '任务 2', completed: false }
    ];
    return (
        <ul>
            {tasks.map(task => (
                <li key={task.id}>
                    {task.text} - {task.completed? '已完成' : '未完成'}
                    {task.subTasks && (
                        <ul>
                            {task.subTasks.map(subTask => (
                                <li key={subTask.id}>
                                    {subTask.text} - {subTask.completed? '已完成' : '未完成'}
                                    {subTask.completed? <span>✅</span> : <span>❌</span>}
                                </li>
                            ))}
                        </ul>
                    )}
                </li>
            ))}
        </ul>
    );
}

export default NestedConditionalList;

在上述代码中,首先判断任务是否有子任务,如果有则进行渲染。在子任务列表项中,又根据子任务的完成状态显示不同的图标。

条件渲染与表单处理

根据表单输入进行条件渲染

在表单处理中,条件渲染可以根据用户的输入来显示不同的内容。例如,一个简单的登录表单,根据用户选择的登录方式(用户名/邮箱)来显示相应的输入框。

import React, { useState } from'react';

function LoginForm() {
    const [loginType, setLoginType] = useState('username');
    return (
        <form>
            <label>
                选择登录方式:
                <select onChange={e => setLoginType(e.target.value)}>
                    <option value="username">用户名</option>
                    <option value="email">邮箱</option>
                </select>
            </label>
            {loginType === 'username' && (
                <input type="text" placeholder="请输入用户名" />
            )}
            {loginType === 'email' && (
                <input type="email" placeholder="请输入邮箱" />
            )}
            <input type="submit" value="登录" />
        </form>
    );
}

export default LoginForm;

在这个例子中,通过 loginType 状态来决定显示用户名输入框还是邮箱输入框。用户在选择登录方式时,loginType 状态改变,从而触发条件渲染。

表单验证与条件渲染

表单验证也是条件渲染的常见应用场景。例如,在注册表单中,当用户输入密码后,根据密码强度显示不同的提示信息。

import React, { useState } from'react';

function SignupForm() {
    const [password, setPassword] = useState('');
    const passwordStrength = password.length >= 8 && /[A - Za - z]/.test(password) && /[0 - 9]/.test(password)?'strong' : 'weak';
    return (
        <form>
            <label>
                密码:
                <input
                    type="password"
                    value={password}
                    onChange={e => setPassword(e.target.value)}
                />
            </label>
            {passwordStrength ==='strong' && <p>密码强度高。</p>}
            {passwordStrength === 'weak' && <p>密码强度低,请包含字母和数字且长度至少 8 位。</p>}
            <input type="submit" value="注册" />
        </form>
    );
}

export default SignupForm;

在上述代码中,通过 passwordStrength 判断密码强度,并根据强度显示不同的提示信息。这使得用户在输入密码时能实时了解密码的安全性。

提交表单后的条件渲染

当表单提交后,也可以根据提交结果进行条件渲染。例如,在登录表单提交后,根据服务器返回的状态来显示登录成功或失败的提示。

import React, { useState } from'react';

function LoginSubmit() {
    const [isLoggedIn, setIsLoggedIn] = useState(false);
    const [error, setError] = useState('');
    const handleSubmit = (e) => {
        e.preventDefault();
        // 模拟登录请求
        setTimeout(() => {
            const success = true; // 假设登录成功
            if (success) {
                setIsLoggedIn(true);
            } else {
                setError('用户名或密码错误');
            }
        }, 1000);
    };
    return (
        <form onSubmit={handleSubmit}>
            <input type="text" placeholder="用户名" />
            <input type="password" placeholder="密码" />
            <input type="submit" value="登录" />
            {isLoggedIn && <p>登录成功!</p>}
            {error && <p style={{ color:'red' }}>{error}</p>}
        </form>
    );
}

export default LoginSubmit;

在这个例子中,当用户点击登录按钮时,模拟登录请求。根据模拟结果,设置 isLoggedInerror 状态,然后通过条件渲染显示相应的提示信息。

条件渲染在 React Router 中的应用

根据路由进行条件渲染

React Router 是 React 应用中常用的路由管理库。我们可以根据当前路由来进行条件渲染。例如,在一个单页应用中,根据不同的页面显示不同的导航栏。

import React from'react';
import { BrowserRouter as Router, Routes, Route, Link } from'react - router - dom';

function Home() {
    return <h1>首页</h1>;
}

function About() {
    return <h1>关于我们</h1>;
}

function App() {
    return (
        <Router>
            <div>
                <nav>
                    <Link to="/">首页</Link>
                    <Link to="/about">关于</Link>
                </nav>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                </Routes>
                {window.location.pathname === '/' && <p>这是首页的特色内容。</p>}
                {window.location.pathname === '/about' && <p>这是关于页面的介绍。</p>}
            </div>
        </Router>
    );
}

export default App;

在上述代码中,通过 window.location.pathname 获取当前路由路径,然后根据路径进行条件渲染,在不同页面显示不同的附加内容。

嵌套路由中的条件渲染

在嵌套路由中,条件渲染同样有用。比如,一个文章详情页面,根据文章类型显示不同的子内容。

import React from'react';
import { BrowserRouter as Router, Routes, Route, Link } from'react - router - dom';

function ArticleList() {
    return (
        <div>
            <ul>
                <li><Link to="/article/1">文章 1(技术类)</Link></li>
                <li><Link to="/article/2">文章 2(生活类)</Link></li>
            </ul>
        </div>
    );
}

function TechnologyArticle() {
    return <p>这是一篇技术类文章。</p>;
}

function LifeArticle() {
    return <p>这是一篇生活类文章。</p>;
}

function Article() {
    const articleType = window.location.pathname.includes('1')? 'technology' : 'life';
    return (
        <div>
            {articleType === 'technology' && <TechnologyArticle />}
            {articleType === 'life' && <LifeArticle />}
        </div>
    );
}

function App() {
    return (
        <Router>
            <div>
                <Routes>
                    <Route path="/article" element={<ArticleList />}>
                        <Route path=":id" element={<Article />} />
                    </Route>
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在这个例子中,根据文章的 ID 判断文章类型,然后在文章详情页面根据类型进行条件渲染,显示不同的文章内容。

基于路由参数的条件渲染

路由参数也可以用于条件渲染。例如,在一个商品详情页面,根据商品类别参数显示不同的推荐商品。

import React from'react';
import { BrowserRouter as Router, Routes, Route, Link, useParams } from'react - router - dom';

function ProductList() {
    return (
        <div>
            <ul>
                <li><Link to="/product/electronics">电子产品</Link></li>
                <li><Link to="/product/clothes">服装</Link></li>
            </ul>
        </div>
    );
}

function ElectronicsRecommend() {
    return <p>推荐电子产品:手机、电脑等。</p>;
}

function ClothesRecommend() {
    return <p>推荐服装:T恤、裤子等。</p>;
}

function Product() {
    const { category } = useParams();
    return (
        <div>
            {category === 'electronics' && <ElectronicsRecommend />}
            {category === 'clothes' && <ClothesRecommend />}
        </div>
    );
}

function App() {
    return (
        <Router>
            <div>
                <Routes>
                    <Route path="/product" element={<ProductList />}>
                        <Route path=":category" element={<Product />} />
                    </Route>
                </Routes>
            </div>
        </Router>
    );
}

export default App;

在上述代码中,通过 useParams 获取路由参数 category,然后根据参数值进行条件渲染,显示不同类别的推荐商品。

通过以上全面的介绍,相信你对 React 条件渲染有了深入的理解和掌握,可以在实际项目中灵活运用条件渲染技术来构建动态、高效的用户界面。无论是简单的判断还是复杂的业务逻辑,React 的条件渲染机制都能为你提供强大的支持。