一道React缓存的题目

界面效果:

要求正确缓存表格的Header组件,当只修改bodyData,不触发TableHeader组件渲染。

实现思路:

结合memo和useMemo缓存Header组件。以下HTML文件可直接在浏览器打开查看效果。

javascript 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>银行流水</title>
    <style>
        /* 表格样式 */
        table {
            border-collapse: collapse;
            width: 600px;
            font-family: Arial, sans-serif;
        }

        th,
        td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }

        th {
            background-color: #f2f2f2;
        }

        /* 按钮样式 */
        button {
            margin-top: 16px;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 14px;
            border-radius: 4px;
        }

        button:hover {
            background-color: #45a049;
        }

        /* 选择框样式 */
        .select-wrapper {
            margin-bottom: 8px;
            position: relative;
            display: inline-block;
        }

        .select-wrapper select {
            appearance: none;
            -webkit-appearance: none;
            -moz-appearance: none;
            background-color: transparent;
            border: 1px solid #ddd;
            padding: 8px;
            font-size: 14px;
            width: 120px;
            cursor: pointer;
            outline: none;
            position: relative;
            z-index: 2;
        }

        .select-wrapper::after {
            content: '▼';
            position: absolute;
            top: 50%;
            right: 8px;
            transform: translateY(-50%);
            pointer-events: none;
            color: #888;
            z-index: 1;
        }

        .select-wrapper::before {
            content: '';
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            background-color: transparent;
            pointer-events: none;
            z-index: 0;
        }
    </style>
</head>

<body>
<div id="root"></div>

<script src="https://static.nowcoder.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://static.nowcoder.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>
<script src="https://static.nowcoder.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>

<script type="text/babel">
    const {useState, useEffect, useMemo, memo} = React;


    // 修改补充TableHeader组件,实现TableHeader组件缓存效果:当只修改bodyData,不触发TableHeader组件渲染
    const TableHeader = memo(({headerData}) => {
        console.log('TableHeader rendered');
        return (
            <thead>
            <tr>
                {headerData.map((header, index) => (
                    <th key={index}>{header}</th>
                ))}
            </tr>
            </thead>
        );
    });

    function TableBody({bodyData}) {
        function dealdate(dealdate) {
            const date = new Date(dealdate)
            const year = date.getFullYear()
            let month = date.getMonth() + 1
            month = month < 10 ? "0" + month : month
            let day = date.getDate()
            day = day < 10 ? "0" + day : day
            return year + '-' + month + '-' + day;
        }


        return (
            <tbody>
            {bodyData.map((row) => (
                <tr key={row.id}>
                    <td>{dealdate(row.date)}</td>
                    <td>{row.type}{row.amount}</td>
                </tr>
            ))}
            </tbody>
        );
    }

    function Table({headerData, initialBodyData, lang}) {
        const [selectedYear, setSelectedYear] = useState(new Date().getFullYear());
        const [bodyData, setBodyData] = useState([]);

        useEffect(() => {
            // 参考上下文,在此补全代码实现根据当前选中"年"数据,展示对应"年"的流水信息
            setBodyData(initialBodyData.filter(item => {
                return item.date.getFullYear() === selectedYear;
            }));


        }, [selectedYear, initialBodyData]);

        // 参考上下文,在下方填写代码,实现效果:
        // 1. 定义一个memoizedData作为传递给TableHeader组件的数据
        // 2. memoizedData数据根据lang取值,lang为'zh-CN'值为['日期', '金额(人民币)'],lang为'English'值为 ['Date', 'Amount(RMB)']
        // 3. 实现TableHeader组件缓存效果:当只修改bodyData,不触发TableHeader组件渲染

        const memoizedData = useMemo(() => {
            if (lang === 'zh-CN') {
                return ['日期', '金额(人民币)'];
            }

            if (lang === 'English') {
                return ['Date', 'Amount(RMB)'];
            }
        }, [lang]);

        const handleYearChange = (event) => {
            const selectedYear = parseInt(event.target.value);
            setSelectedYear(selectedYear);
        };

        return (
            <div>
                <div className="select-wrapper">
                    <select value={selectedYear} onChange={handleYearChange} class='year'>
                        <option value={2022}>2022年</option>
                        <option value={2023}>2023年</option>
                        <option value={2024}>2024年</option>
                    </select>
                </div>
                <table>
                    <TableHeader headerData={memoizedData}/>
                    <TableBody bodyData={bodyData}/>
                </table>
            </div>
        );
    }

    function App() {
        const headerData = ['日期', '金额(人民币)'];
        const initialBodyData = [
            {id: 1, date: new Date('2022-01-01'), amount: 1000, type: '-'},
            {id: 2, date: new Date('2022-01-05'), amount: 500, type: '-'},
            {id: 3, date: new Date('2022-01-10'), amount: 2000, type: '+'},
            {id: 4, date: new Date('2023-02-12'), amount: 800, type: '-'},
            {id: 5, date: new Date('2023-03-20'), amount: 150, type: '+'},
            {id: 6, date: new Date('2024-01-02'), amount: 300, type: '-'},
            {id: 7, date: new Date('2024-01-03'), amount: 2500, type: '+'},
            {id: 8, date: new Date('2024-01-04'), amount: 500, type: '-'},
            {id: 9, date: new Date('2024-01-15'), amount: 500, type: '+'}
        ];

        const [lang, setLang] = useState('zh-CN');

        return (
            <div>
                <div className="select-wrapper">
                    <select value={lang} onChange={(e) => setLang(e.target.value)} class='lang'>
                        <option value="zh-CN">中文</option>
                        <option value="English">English</option>
                    </select>
                </div>
                <Table headerData={headerData} initialBodyData={initialBodyData} lang={lang}/>
            </div>
        );
    }

    ReactDOM.render(<App/>, document.getElementById('root'));
</script>
</body>

</html>
相关推荐
一颗烂土豆20 分钟前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
YFF菲菲兔1 小时前
调度系统和调和系统的桥梁
react.js
kyriewen3 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly5 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
YFF菲菲兔5 小时前
commitRoot 源码解析
react.js
假如让我当三天老蒯6 小时前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒7 小时前
Bun 哪比 Node.js 快?
javascript·后端
JieE21215 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong18 小时前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨1 天前
深入理解 JavaScript 事件循环
前端·javascript