useRef 定义的 ref 在控制台可以打印但是页面不生效?

文章讲述了如何在React中使用useRef创建计数器,尽管useRef不会自动触发渲染,但通过useState实现状态管理解决了计数器值更新问题。

useRef 是一个 React Hook,它能让你引用一个不需要渲染的值。

点击计时器

点击按钮后在控制台可以打印但是页面不生效。

image.png

useRef 返回的值在函数组件中不会自动触发重新渲染,所以控制台可以显示变化而按钮上无法显示 ref.current的变化。

import { useRef } from "react";

const ClinkNumber = () => {
  let ref = useRef(0);

  function handleClick() {
    ref.current = ref.current + 1;
    // 每次触发函数会跟随变动 +1
    console.log(ref.current);
  }

  return (
    <div>
      // ref.current 不会跟随变动
      <button onClick={handleClick}>点击计时器 {ref.current}</button>
    </div>
  );
};

export default ClinkNumber;

解决这个问题的方法是使用 React 的状态管理来保存并更新计数器的值。

const [counter, setCounter] = useState(0);

<script type="text/babel"> const ChatRoom = () => { const [messages, setMessages] = React.useState([]); const [inputValue, setInputValue] = React.useState(""); const [ws, setWs] = React.useState(null); const messagesEndRef = React.useRef(null); // 滚动到底部 const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; React.useEffect(() => { scrollToBottom(); }, [messages]); React.useEffect(() => { const websocket = new WebSocket(`ws://${window.location.host}/ws`); websocket.onopen = () => { console.log("✅ 已连接到聊天室"); setWs(websocket); }; websocket.onmessage = (event) => { const data = JSON.parse(event.data); setMessages(prev => [...prev, data]); }; websocket.onclose = () => { console.log("❌ 聊天室连接已关闭"); alert("与服务器断开连接"); }; websocket.onerror = (err) => { console.error("WebSocket 错误:", err); }; return () => { websocket.close(); }; }, []); const goHome = () => { window.location.href = '/'; } const sendMessage = () => { if (!inputValue.trim() || !ws || ws.readyState !== WebSocket.OPEN) return; const msg = { type: "chat", content: inputValue.trim() }; ws.send(JSON.stringify(msg)); setInputValue(""); }; const handleKeyDown = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; return ( <div className="chat-container"> <div class="chat-header-bar"> <button class="circle-button" onclick={goHome}> < </button> <div class="chat-header"> <h2>💬 AI 实时聊天室</h2> <p>当前用户: {{ stu_id }}</p> </div> </div> <div className="chat-messages"> {messages.length === 0 ? ( <p className="no-messages">暂无消息,开始对话吧!</p> ) : ( messages.map((msg, idx) => ( <div key={idx} className={`message ${msg.stu_id === '{{ stu_id }}' ? 'own' : 'other'}`}> <strong>{msg.stu_id}</strong> <p>{msg.content}</p> <small>{new Date(msg.timestamp * 1000).toLocaleTimeString()}</small> </div> )) )} <div ref={messagesEndRef} /> </div> <div className="chat-input-area"> <textarea value={inputValue} onChange={(e) => setInputValue(e.target.value)} onKeyDown={handleKeyDown} placeholder="输入消息..." rows="2" maxLength="500" /> <button onClick={sendMessage} disabled={!inputValue.trim()}> 发送 </button> </div> </div> ); }; ReactDOM.createRoot(document.getElementById('root')).render(<ChatRoom />); </script> 为什么onclick无法触发goHome
最新发布
11-12
### 原因分析与解决方案 在使用 Ant Design 3.x 的 `Upload` 组件时,若通过 `ref={(ref) => uploadRef = ref}` 设置 `ref` 后发现 `uploadRef.current` 为 `undefined`,通常是由于组件未正确暴露其内部 DOM 节点或未正确使用 `ref` 所致。 Ant Design 3.x 的组件默认不会将 `ref` 指向其内部的 DOM 元素,而是指向组件实例本身。如果组件未显式支持 `ref` 传递,则 `uploadRef.current` 将无法获取到有效的 DOM 节点或组件实例。对于 `Upload` 组件,其内部的 `<input type="file">` 元素才是触发文件选择对话框的关键节点,因此需确保 `ref` 能够正确访问到该节点。 在 React 中,若希望将 `ref` 传递到子组件的内部 DOM 元素,需要使用 `forwardRef` 和 `useRef` 配合实现。虽然 Ant Design 的 `Upload` 是封装好的组件,无法直接使用 `forwardRef`,但可以通过 `ref` 获取组件实例后,访问其内部的 `input` 属性来获取 `<input type="file">` 元素,从而调用 `click()` 方法触发文件选择框。 以下为实现代码示例: ```jsx import React, { useRef } from 'react'; import { Upload, Button } from 'antd'; import { UploadOutlined } from '@ant-design/icons'; const ManualUpload = () => { const uploadRef = useRef(null); const openFileDialog = () => { if (uploadRef.current && uploadRef.current.input) { uploadRef.current.input.click(); } }; return ( <div> <Upload ref={uploadRef} action="https://www.mocky.io/v2/5cc8019d300000980a055e76" listType="picture-card" beforeUpload={() => false} accept="image/*" > <div style={{ display: 'none' }}> <Button icon={<UploadOutlined />}>Select File</Button> </div> </Upload> <Button type="primary" onClick={openFileDialog} icon={<UploadOutlined />}> 手动选择文件 </Button> </div> ); }; export default ManualUpload; ``` 在上述代码中,`ref={uploadRef}` 被绑定到 `Upload` 组件实例上,通过 `uploadRef.current.input` 可访问其内部的文件选择 `<input>` 元素。若 `uploadRef.current` 仍为 `undefined`,则可能是组件未正确完成渲染,或在非预期的生命周期阶段尝试访问该引用。为确保组件已挂载,可以在 `useEffect` 中进行检查: ```jsx import React, { useRef, useEffect } from 'react'; const ManualUpload = () => { const uploadRef = useRef(null); useEffect(() => { if (uploadRef.current) { console.log('Upload component is mounted'); } }, []); return ( // Upload 组件配置 ); }; ``` ### 相关问题 1. 如何在 Ant Design 4.x 中实现手动触发 Upload 文件选择? 2. React 中如何通过 ref 获取 Ant Design 组件的底层 DOM 元素? 3. 如何阻止 Ant Design Upload 组件自动上传文件?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值