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

React useState问题:无法将子组件Toggle状态传递给父组件

问题描述

我需要将一个对象数组映射渲染成多个Toggle子组件,希望根据Toggle的开关状态更新数组中对应对象的state属性,但不知道怎么把子组件中特定对象的Toggle状态传递回父组件。

父组件原代码

import { useState, useEffect } from "react";
import { RadioGroup } from "@headlessui/react";
import Toggle from "./Toggle";

const frameVariants= [
  {
    key: "1",
    name: "Caisse américaine",
    description: "Aucun aperçu disponible pour le moment",
    state: true,
  },
  {
    key: "2",
    name: "Photo encadrée",
    description: "Aucun aperçu disponible pour le moment",
    state: true,
  }
];

function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function TableToggle(props) {
  const [selected, setSelected] = useState(frameVariants[0]);
  const [details, showDetails] = useState(true);


  return (
    <RadioGroup defaultValue={props.defaultValue} onChange={props.onChange}>
      <RadioGroup.Label className="sr-only">Privacy setting</RadioGroup.Label>
      <div className="bg-gray-50 shadow-inner rounded-md -space-y-px">
        {frameVariants.map((variant, variantIdx) => (
          <div key={variant.key}>
            <RadioGroup.Option
              key={variant.key}
              value={variant.name}>
                <>
                  <span
                    className=""
                    aria-hidden=""
                  >
                    <Toggle id={variant.key} variant={variant}/>
                  </span>
                 
                </>
            </RadioGroup.Option>
          </div>
      </div>
    </RadioGroup>
  );
}

子组件原代码

import { useState } from "react";
import { Switch } from "@headlessui/react";

function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function Toggle(props) {
  const [enabled, setEnabled] = useState(props.variant);

  const handleToggleState = () => {
    setEnabled((val) => !val)};

  return (
    <Switch
      key={props.id}
      checked={enabled}
      onChange={handleToggleState}
      
      className={classNames(
        enabled ? "bg-indigo-600" : "bg-gray-200",
        "relative inline-flex flex-shrink-0 h-5 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
      )}
    >
      <span className="sr-only">Use setting</span>
      <span
        aria-hidden="true"
        className={classNames(
          enabled ? "translate-x-5" : "translate-x-0",
          "pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
        )}
      />
    </Switch>
  );
}
解决方案

核心思路是状态提升:把Toggle的状态统一放在父组件维护,子组件只负责渲染开关和触发状态变化的回调,这样父组件就能直接更新数组里的对应对象。

1. 修改父组件

  • 把frameVariants从常量改成useState状态,确保数组内容可修改
  • 新增handleToggleChange函数,通过对象的key定位要更新的数组项,修改其state属性
  • 给Toggle组件传递当前的checked状态和触发更新的回调函数

修改后的父组件代码:

import { useState, useEffect } from "react";
import { RadioGroup } from "@headlessui/react";
import Toggle from "./Toggle";

// 初始数据作为useState默认值
const initialFrameVariants = [
  {
    key: "1",
    name: "Caisse américaine",
    description: "Aucun aperçu disponible pour le moment",
    state: true,
  },
  {
    key: "2",
    name: "Photo encadrée",
    description: "Aucun aperçu disponible pour le moment",
    state: true,
  }
];

function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function TableToggle(props) {
  const [selected, setSelected] = useState(initialFrameVariants[0]);
  const [details, showDetails] = useState(true);
  // 将数组转为可修改的状态
  const [frameVariants, setFrameVariants] = useState(initialFrameVariants);

  // 处理Toggle状态变化:通过key定位并更新对应对象的state
  const handleToggleChange = (key, newState) => {
    setFrameVariants(prev => 
      prev.map(item => 
        item.key === key ? {...item, state: newState} : item
      )
    );
  };

  return (
    <RadioGroup defaultValue={props.defaultValue} onChange={props.onChange}>
      <RadioGroup.Label className="sr-only">Privacy setting</RadioGroup.Label>
      <div className="bg-gray-50 shadow-inner rounded-md -space-y-px">
        {frameVariants.map((variant) => (
          <div key={variant.key}>
            <RadioGroup.Option
              key={variant.key}
              value={variant.name}>
                <>
                  <span
                    className=""
                    aria-hidden=""
                  >
                    {/* 传递checked状态和回调函数 */}
                    <Toggle 
                      id={variant.key} 
                      checked={variant.state}
                      onChange={(newState) => handleToggleChange(variant.key, newState)}
                    />
                  </span>
                </>
            </RadioGroup.Option>
          </div>
        ))}
      </div>
    </RadioGroup>
  );
}

2. 修改子组件

  • 删除子组件自身的enabled状态,直接使用父组件传递的checked属性
  • 修改handleToggleState,触发父组件传入的onChange回调,将新状态值回传

修改后的子组件代码:

import { Switch } from "@headlessui/react";

function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function Toggle(props) {
  // 直接转发状态变化给父组件
  const handleToggleState = (newState) => {
    props.onChange(newState);
  };

  return (
    <Switch
      key={props.id}
      checked={props.checked}
      onChange={handleToggleState}
      
      className={classNames(
        props.checked ? "bg-indigo-600" : "bg-gray-200",
        "relative inline-flex flex-shrink-0 h-5 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
      )}
    >
      <span className="sr-only">Use setting</span>
      <span
        aria-hidden="true"
        className={classNames(
          props.checked ? "translate-x-5" : "translate-x-0",
          "pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
        )}
      />
    </Switch>
  );
}

改动说明

  • 父组件完全控制所有Toggle的状态,每次切换时会精准更新数组中对应对象的state属性
  • 子组件变为受控组件,仅负责渲染和转发状态变化,无内部状态,状态流转更清晰
  • 利用对象的key作为唯一标识,确保能准确找到要更新的数组项

内容的提问来源于stack exchange,提问作者Yann D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:48:14