You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React开发鼠标轨迹记录页时mousemove事件仅在点击后触发问题

问题根因

你当前代码中的records数组实际上已经在鼠标移动时正常更新,只是你仅在点击按钮的逻辑中打印该数组、同时控制列表渲染的displayMessage默认值为false,才会产生只有点击按钮时数组才更新的错觉。不过代码存在几个实际bug需要修复:

  • 事件监听移除失效:addEventListener和removeEventListener传入的是两个独立的匿名箭头函数,引用不一致,组件卸载时无法正确移除mousemove监听,会造成内存泄漏。
  • 性能损耗严重:每次鼠标移动都调用setState触发组件重渲染,当记录数较多、且开启展示时,全量重渲染列表会导致页面卡顿。
  • 列表key值不规范:使用indexOf(record)作为key值,每次数组更新都会重新计算所有项的索引,进一步降低渲染性能。

修复方案

  • 把mousemove监听函数存为实例属性,保证添加和移除的是同一个引用
  • 用ref存储轨迹数据,避免频繁触发重渲染,仅在点击按钮需要展示时才把数据同步到state
  • 给每条轨迹生成唯一key值

修复后完整代码

import React, {Component, createRef} from 'react';

class MouseRecord extends Component {
    constructor(props) {
        super(props);

        this.state = {
            displayMessage: false,
            showRecords: []
        }
        // 用ref存储轨迹数据,不触发频繁重渲染
        this.recordsRef = { current: [] }
        // 把监听函数存为实例属性,保证添加和移除是同一个引用
        this.mouseMoveHandler = this.handleMouseMove.bind(this)

        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        // 点击按钮时才把ref的数据同步到state,触发渲染
        this.setState(prevState => ({
            displayMessage: !prevState.displayMessage,
            showRecords: this.recordsRef.current
        }));
    }

    handleMouseMove(e) {
        e.preventDefault();
        if (this.recordsRef.current.length <= 100000){
            this.recordsRef.current.push({
                cor_X: e.clientX,
                cor_Y: e.clientY,
                width: window.innerWidth,
                height: window.innerHeight,
                timestamp: new Date().toUTCString()
            })
        }
    }

    componentDidMount() {
        document.addEventListener('mousemove', this.mouseMoveHandler);
    }

    componentWillUnmount() {
        document.removeEventListener('mousemove', this.mouseMoveHandler);
    }

    render(){
        return(
            <div className="box">
                <button onClick={this.handleClick}>点击获取鼠标轨迹记录</button>
                <div>
                    {this.state.displayMessage && this.state.showRecords.length > 0 ? this.state.showRecords.map((record, index) => {
                        return (
                            <div key={`${record.timestamp}-${record.cor_X}-${record.cor_Y}-${index}`}>
                                <p>X坐标: {record.cor_X}</p>
                                <p>Y坐标: {record.cor_Y}</p>
                                <p>窗口宽度: {record.width}</p>
                                <p>窗口高度: {record.height}</p>
                                <p>时间戳: {record.timestamp}</p>
                                <br/>
                                <br/>
                            </div>
                        );
                    }) : null}
                </div>
            </div>
        );
    }
}

export default MouseRecord;

内容的提问来源于stack exchange,提问作者Benedict Howard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 13:57:03