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

React组件单选组选中后值无法更新问题排查

单选按钮状态不更新问题排查与解决

我开发了一个React组件,支持通过文本框输入文本,并从8个单选按钮中选择对应格式。使用useState实时管理状态变化,但无论选择哪个选项,返回的selectedStyle值始终为初始值"ama"。添加console.log(selectedStyle)跟踪状态,发现始终输出"ama";将RadioGroup的value={selectedStyle}改为defaultValue={selectedStyle}后,选中的单选按钮会高亮,但selectedStyle的值仍保持"ama"。

组件代码如下:

"use client"

import { useState, useRef } from "react"
import { Copy } from "lucide-react"
import { Button } from "./ui/button"
import { Textarea } from "./ui/textarea"
import toTitleCase from "../lib/toTitleCase"

import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip"

function TitleCaseInput() {
  const [value, setValue] = useState("")
  const [selectedStyle, setSelectedStyle] = useState("ama")

  const textareaRef = useRef<HTMLTextAreaElement>(null)

  const handleTextareaHover = () => {
    if (textareaRef.current && !textareaRef.current.disabled) {
      textareaRef.current.focus()
    }
  }

  const handleTextareaChange = (
    event: React.ChangeEvent<HTMLTextAreaElement>,
  ) => {
    const input = event.target.value
    const output = toTitleCase(input, selectedStyle)
    setValue(output)
  }

  const handleCopyClick = () => {
    navigator.clipboard.writeText(value)
  }

  const styles = [
    "AMA",
    "AP",
    "APA",
    "Bluebook",
    "Chicago",
    "MLA",
    "NYT",
    "Wikipedia",
  ]
  const styleTips = [
    "American Medical Association Manual of Style",
    "The Associated Press Stylebook",
    "Publication Manual of the American Psychological Association",
    "The Bluebook: A Uniform System of Citation",
    "The Chicago Manual of Style",
    "The Modern Language Association Style Manual",
    "The New York Times Manual of Style and Usage",
    "Wikipedia: Manual of Style",
  ]

  // console.log(selectedStyle)

  return (
    <div className="mx-2 flex flex-row gap-3 md:mx-4 md:last:mb-6 lg:mx-auto lg:max-w-full xl:max-w-8xl">
      <div className="relative flex h-full flex-1 items-stretch md:flex-col">
        <div className="relative flex flex-col w-full flex-grow p-4">
          <div className="relative">
            <Textarea
              ref={textareaRef}
              value={value}
              onChange={handleTextareaChange}
              onMouseEnter={handleTextareaHover}
              rows={1}
              maxRows={10}
              autoFocus
              placeholder="Your unformatted title..."
              className="resize-none pr-12 text-base py-3 scrollbar-thumb-blue scrollbar-thumb-rounded scrollbar-track-blue-lighter scrollbar-w-2 scrolling-touch"
            />
            <Button
              className="absolute bottom-1.5 right-[8px]"
              variant="ghost"
              aria-label="convert"
              onClick={handleCopyClick}
            >
              <Copy
                className={`text-green-600 ${value ? "" : "text-gray-400"}`}
              />
            </Button>
          </div>
          <h2 className="mb-3 mt-6 font-bold text-2xl">Style Guide</h2>
          <div>
            <TooltipProvider>
              <RadioGroup
                defaultValue="ama"
                value={selectedStyle}
                onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
                  setSelectedStyle(event.target.value)
                }
                className="grid xs:grid-cols-2 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-8 gap-4"
              >
                {styles.map((style, index) => (
                  <div key={style} className="col-span-1 space-x-2">
                    <Tooltip>
                      <RadioGroupItem
                        value={style.toLowerCase()}
                        id={`style${index + 1}`}
                      />
                      <TooltipTrigger asChild>
                        <Label htmlFor={`style${index + 1}`}>{style}</Label>
                      </TooltipTrigger>
                      <TooltipContent className="bg-gray-600 text-white">
                        <p>{styleTips[index]}</p>
                      </TooltipContent>
                    </Tooltip>
                  </div>
                ))}
              </RadioGroup>
            </TooltipProvider>
          </div>
        </div>
      </div>
    </div>
  )
}

export default TitleCaseInput

问题原因

shadcn/ui的RadioGroup组件的onChange回调参数并非React.ChangeEvent<HTMLInputElement>,而是直接返回选中的字符串值。你当前的代码试图访问event.target.value,但这里的event其实是选中的字符串,导致target属性不存在,代码执行出错,setSelectedStyle根本没有被调用,所以状态始终保持初始值。

解决方案

修改RadioGroup的onChange回调,直接接收选中的值作为参数:

<RadioGroup
  defaultValue="ama"
  value={selectedStyle}
  // 直接接收value参数,而非event对象
  onChange={(value) => setSelectedStyle(value)}
  className="grid xs:grid-cols-2 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-8 gap-4"
>

修改后,选择单选按钮时selectedStyle状态会正常更新,文本框也会根据选中的格式实时转换文本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:56:07