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

如何让goUp与goDown函数在.jsx文件中正常工作?

解决React中textarea滚动控制失效的问题

问题根源

你代码里的核心问题是初始化时过早获取DOM元素:在组件顶层直接调用document.getElementById("textt"),此时React还未完成DOM渲染,okayy的值为null。点击按钮时传递的是null,滚动方法自然无法执行。即使后续DOM渲染完成,组件状态更新导致重新渲染时,okayy会被重新赋值,仍可能出现获取不到元素的情况。

修复方案

使用React官方推荐的useRef钩子来获取DOM元素,它能在组件生命周期内稳定保存DOM引用,避免上述问题。

修改后的完整代码

import { useState, useRef } from 'react' // 新增useRef导入
import Dialog from '@mui/material/Dialog'
import Button from '@mui/material/Button'
import CircularProgress from '@mui/material/CircularProgress'
import CloseIcon from '@mui/icons-material/Close'
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'
import { styled } from '@mui/material/styles'
import { UpdateBookModalForm } from './updateBookModalSkin'
import { updateBook } from 'api/book'
import Toast from 'shared/Toast'
import { queryClient } from 'App'
import AppContainer from '../../appSkin.js'

// 补全BootstrapDialog的定义(原代码未导入,需确保样式正确)
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
  // 若无自定义样式可直接使用Dialog组件
}))

const UpdateBookModal = ({
    book_id,
    book_title,
    book_author,
    book_issn,
    book_note,
    handleClose,
    modalOpen,
}) => {
    // 用useRef创建textarea的DOM引用,替代document.getElementById
    const textareaRef = useRef(null);

    // 补充状态初始值,优化组件初始化体验
    const [bookTitle, setBookTitle] = useState(book_title)
    const [author, setAuthor] = useState(book_author)
    const [issn, setIssn] = useState(book_issn)
    const [note, setNote] = useState(book_note)
    const [bookUpdating, setBookUpdating] = useState(false)
    const [toastMessage, setToastMessage] = useState('')
    const [toastType, setToastType] = useState('')
    const [toastOpen, setToastOpen] = useState(false)

    const goUp = (element) => {
        if (!element) return; // 增加空值判断,避免报错
        if (element.scrollTop !== 0) {
            element.scrollTo({
                top: element.scrollTop - 10,
                left: 0,
                behavior: "smooth"
            });
        }
    };
    const goDown = (element) => {
        if (!element) return; // 增加空值判断
        element.scrollTo({
            top: element.scrollTop + 10,
            left: 0,
            behavior: "smooth"
        });
    };

    const handleSubmit = async ev => {
        ev.preventDefault()

        setBookUpdating(true)

        const result = await updateBook(book_id, {
            book_title: bookTitle,
            book_author: author,
            book_issnisbn: issn,
            book_notes: note,
        })

        setBookUpdating(false)
        handleClose()
        setToastOpen(true)

        if (result.error) {
            setToastType('error')
            if (result.error.response) {
                setToastMessage(result.error.response.data.message)
            } else if (result.error.request) {
                setToastMessage(result.error.request)
            } else {
                setToastMessage(result.error.message)
            }
        } else {
            setToastType('success')
            setToastMessage('Book updated successfully!')
            queryClient.invalidateQueries('books')
        }
    }

    const toastClose = (event, reason) => {
        if (reason === 'clickaway') {
            return
        }

        setToastOpen(false)
    }

    return (
        <BootstrapDialog
            onClose={handleClose}
            aria-labelledby="customized-dialog-title"
            open={modalOpen}
        >
            <UpdateBookModalForm onSubmit={handleSubmit}>
                <AppContainer>
                    <div className="modal_top">
                        <input
                            style={{ lineHeight: 2.5 }}
                            className="h8 input-box font"
                            type="text"
                            placeholder="TITLE"
                            value={bookTitle}
                            onChange={ev => setBookTitle(ev.target.value)}
                        />

                        <span className="close-icon" onClick={handleClose}>
                            <CloseIcon />
                        </span>
                    </div>

                    {/* 修改点击事件,传递ref.current */}
                    <div className="top" onClick={() => goUp(textareaRef.current)}>
                        <KeyboardArrowUpIcon style={{ cursor: 'pointer' }} />
                    </div>
                    {/* 将ref绑定到textarea元素 */}
                    <textarea
                        ref={textareaRef}
                        rows="4"
                        cols="50"
                        maxLength="400"
                        className="h8 text-box font"
                        placeholder="YOUR NOTES"
                        value={note}
                        onChange={ev => setNote(ev.target.value)}
                    />
                    <div className="bottom" onClick={() => goDown(textareaRef.current)}>
                        <KeyboardArrowDownIcon style={{ cursor: 'pointer' }} />
                    </div>

                    <div className="modal_bottom">
                        <div className='note_buttons_container'>
                            <div className="h7 note">Please note that in most cases we can retrieve <br /> Metadata directly from the uploaded file</div>
                            <div className="buttons">
                                <Button
                                    onClick={handleClose}
                                    variant="contained"
                                    className="h6 login-btn font"
                                >
                                    Cancel
                                </Button>

                                <Button
                                    type="submit"
                                    variant="contained"
                                    className="h6 login-btn"
                                    disabled={bookUpdating}
                                >
                                    {bookUpdating ? (
                                        <CircularProgress
                                            style={{ height: '28px', width: '28px' }}
                                            color="inherit"
                                        />
                                    ) : (
                                        'Save'
                                    )}
                                </Button>
                            </div>
                        </div>
                    </div>
                </AppContainer>
            </UpdateBookModalForm>

            <Toast
                toastClose={toastClose}
                open={toastOpen}
                severity={toastType}
                message={toastMessage}
            />
        </BootstrapDialog>
    )
}

export default UpdateBookModal

关键改动说明

  1. 使用useRef获取DOM元素:替代document.getElementById,确保在DOM挂载后能稳定获取到textarea的引用,不受组件重新渲染影响。
  2. 绑定ref到textarea:通过ref={textareaRef}将DOM元素与ref关联,建立可靠的引用关系。
  3. 传递有效元素引用:点击按钮时传递textareaRef.current,保证每次调用滚动方法时都能拿到最新的DOM元素。
  4. 增加空值防御:在滚动函数中先判断元素是否存在,避免空指针报错。
  5. 补充状态初始值:将props传入的默认值赋值给state,优化组件初始化时的显示效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:45:44