React JS中Copy Text按钮功能异常,请求排查问题
React项目复制文本按钮失效问题排查与修复
问题背景
基于create-react-app开发的项目中,复制文本按钮点击后无反应,控制台报错:
Uncaught TypeError: Cannot read properties of null (reading 'Select')
相关代码如下:
import React, {useState} from 'react' export default function TextForm(props) { const handleCopy = () => { console.log("I am copy"); let text = document.getElementById("mybox"); text.Select(); navigator.clipborad.writetext(text.value); } const handleOnChange = (event) =>{ // console.log("on change"); setText(event.target.value); } const [text, setText] = useState(''); return ( <> <div className='container'> <h1>{props.heading} </h1> <div className="mb-3"> <textarea className="form-control" value={text} id="myBox" rows="8" onChange={handleOnChange}></textarea> <button className="btn btn-primary mx-2 my-2" onClick={handleCopy}>Copy Text</button> </div> </div> <div className="container my-3"> <h2>Your text summary</h2> <p>{text.split(" ").length} Word and {text.length} Characters</p> <p>{0.008 * text.split(" ").length} Minute Read</p> <h3>Preview</h3> <p>{text}</p> </div> </> ) }
错误原因
- ID大小写不匹配:代码中用
document.getElementById("mybox")获取元素,但textarea实际ID是myBox(首字母大写),导致获取结果为null,调用Select()时触发报错。 - 方法名拼写错误:DOM元素的选中方法是
select()(小写s),不是Select()(大写S)。 - Clipboard API拼写错误:
navigator.clipborad应为navigator.clipboard,writetext应为writeText(大写T)。 - 不符合React最佳实践:直接用
document.getElementById操作DOM违背React数据流理念,推荐用useRef获取DOM元素。
修复后的代码
import React, { useState, useRef } from 'react' export default function TextForm(props) { // 用useRef获取textarea元素 const textareaRef = useRef(null); const handleCopy = () => { console.log("I am copy"); // 先判断元素是否存在 if (!textareaRef.current) return; // 选中textarea内容 textareaRef.current.select(); // 调用正确的Clipboard API复制文本 navigator.clipboard.writeText(textareaRef.current.value) .then(() => { console.log("文本已复制到剪贴板"); // 复制后取消选中,提升体验 window.getSelection().removeAllRanges(); }) .catch(err => { console.error("复制失败:", err); }); } const handleOnChange = (event) =>{ setText(event.target.value); } const [text, setText] = useState(''); return ( <> <div className='container'> <h1>{props.heading} </h1> <div className="mb-3"> <textarea className="form-control" value={text} ref={textareaRef} // 绑定ref rows="8" onChange={handleOnChange} ></textarea> <button className="btn btn-primary mx-2 my-2" onClick={handleCopy}>Copy Text</button> </div> </div> <div className="container my-3"> <h2>文本摘要</h2> {/* 优化单词计数,避免空文本或多空格导致的错误 */} <p>{text.trim() ? text.split(/\s+/).length : 0} 个单词,{text.length} 个字符</p> <p>{0.008 * (text.trim() ? text.split(/\s+/).length : 0)} 分钟阅读时长</p> <h3>预览</h3> <p>{text || "请输入文本"}</p> </div> </> ) }
额外优化说明
- 增加空值判断,防止组件未完全挂载时操作DOM报错。
- 优化单词计数逻辑:用正则
/\s+/分割文本,避免多个连续空格误计为单词;空文本时显示0个单词。 - 添加复制成功/失败的日志,方便调试。
- 复制后取消文本选中状态,提升用户体验。
内容的提问来源于stack exchange,提问作者Shubham Bhattaniya
相关产品推荐
相关产品推荐

