更新父状态时,React 复选框卡住了

问题描述 投票:0回答:1

我是React新手,我正在尝试编写一个包含不同组的组件,每个组都积累了点数并且每个组都包含不同的复选框,我希望当单击复选框时,金额将正确更新方式(加/减取决于复选框状态)

这是我的代码,我试图检查它是否工作(我省略了不相关的代码并包含):

export default function Tracker() {

 
const [amountMust, setAmountMust] = React.useState(0); // 84
const [amountListA, setAmountListA] = React.useState(0); // 24.5
const [amountMalag, setAmountMalag] = React.useState(0); //6
const [amountSport, setAmountSport] = React.useState(0); //2
const [amountScience, setAmountScience] = React.useState(0); // 8
const [amountGeneral, setAmountGeneral] = React.useState(0); // 2
const [amountProject, setAmountProject] = React.useState(0); // 2
const [amountEnglish, setAmountEnglish] = React.useState(0); // 2


const courses = [
      { number: "101", name: "Mathematics", points: 3 },
      { number: "102", name: "Physics", points: 4 },
      { number: "103", name: "Chemistry", points: 2 },
    ];

    const CheckBoxState = ({ points, groupSetter }) => {
      const [isChecked, setIsChecked] = React.useState(false);
  
      const handleCheckboxChange = (e) => {
            const newChecked = e.target.checked;
            setIsChecked(newChecked);       
            groupSetter ((prevGroupPoints) =>
            newChecked ? prevGroupPoints + points : prevGroupPoints - points);      
      };
  
      return (
        <Checkbox
          variant="soft"
          size="md"
          color="success"
          checked={isChecked}
          onChange={handleCheckboxChange}
        />
      );
    };

    const CourseList = ({ courses }) => {
      return (
            
        <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {courses.map((course) => (
            <FormControl
              sx={{
                display: "flex",
                flexDirection: "row",
                gap: 1,
                border: "1px solid #ccc",
                borderRadius: 2,
                padding: 2,
              }}
            >
              <Box sx={{ display: "fixed", alignItems: "center", gap: 2 }}>
                <CheckBoxState points={course.points} groupSetter={setAmountMust}/>
                <Typography variant="body2">{course.number}</Typography> 
                <Typography variant="body2">{course.name}</Typography>
                <Typography variant="body2">נק"ז: {course.points}</Typography>
            </Box>
              <Box sx={{ display: "flex", gap: 2, mt: 2, marginLeft: 1 }}>
                <FormControl>
                  <FormLabel>Option 1</FormLabel>
                  <Switch size="sm" />
                </FormControl>
                <FormControl>
                  <FormLabel>Option 2</FormLabel>
                  <Switch size="sm" />
                </FormControl>
              </Box>
            </FormControl>
          ))}
        </Box>
      );
    };


  return (
      <div className='box'>
            <CourseList />
      </div>

  );
}

问题是当在

groupSetter
内调用
handleCheckboxChange
时,复选框状态不会改变并保持未选中状态,并且每次单击时都会将值一遍又一遍地添加到
amountMust
,但是当删除
groupSetter
或将其传递给常规值不依赖于它之前的工作状态。

将状态设置器和值传递给复选框组件的目的是因为我想在代码中将这个组件用于不同的组。

react-native react-hooks material-ui
1个回答
0
投票

不要在其他 React 组件中声明 React 组件。这里的问题是,每次

Tracker
中的状态更新时,
CheckBoxState
CourseList
都被重新声明,并且是 new React 组件引用。 React 将卸载以前的“版本/实例”并安装新的“版本/实例”。他们拥有的任何状态和 UI 也将被重置。

将这些组件声明移至 Tracker 组件声明之外 并传入它们所需的 props,而不是依赖于

Tracker
函数提供的 Javascript 闭包。
示例:

const courses = [ { number: "101", name: "Mathematics", points: 3 }, { number: "102", name: "Physics", points: 4 }, { number: "103", name: "Chemistry", points: 2 }, ];

const CheckBoxState = ({ points, setAmountMust }) => {
  const [isChecked, setIsChecked] = React.useState(false);
  
  const handleCheckboxChange = (e) => {
    const { checked } = e.target;
    setIsChecked(checked);       
    setAmountMust((amountMust) => checked
      ? amountMust + points
      : amountMust - points
    );
  };
  
  return (
    <Checkbox
      variant="soft"
      size="md"
      color="success"
      checked={isChecked}
      onChange={handleCheckboxChange}
    />
  );
};
const CourseList = ({ courses, setAmountMust }) => {
  return (
    <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
      {courses.map((course) => (
        <FormControl
          key={course.name}
          sx={{
            display: "flex",
            flexDirection: "row",
            gap: 1,
            border: "1px solid #ccc",
            borderRadius: 2,
            padding: 2,
          }}
        >
          <Box sx={{ display: "fixed", alignItems: "center", gap: 2 }}>
            <CheckBoxState
              points={course.points}
              setAmountMust={setAmountMust}
            />
            <Typography variant="body2">{course.number}</Typography> 
            <Typography variant="body2">{course.name}</Typography>
            <Typography variant="body2">נק"ז: {course.points}</Typography>
        </Box>
          <Box sx={{ display: "flex", gap: 2, mt: 2, marginLeft: 1 }}>
            <FormControl>
              <FormLabel>Option 1</FormLabel>
              <Switch size="sm" />
            </FormControl>
            <FormControl>
              <FormLabel>Option 2</FormLabel>
              <Switch size="sm" />
            </FormControl>
          </Box>
        </FormControl>
      ))}
    </Box>
  );
};
export default function Tracker() {
  const [amountMust, setAmountMust] = React.useState(0); // 84
  const [amountListA, setAmountListA] = React.useState(0); // 24.5
  const [amountMalag, setAmountMalag] = React.useState(0); //6
  const [amountSport, setAmountSport] = React.useState(0); //2
  const [amountScience, setAmountScience] = React.useState(0); // 8
  const [amountGeneral, setAmountGeneral] = React.useState(0); // 2
  const [amountProject, setAmountProject] = React.useState(0); // 2
  const [amountEnglish, setAmountEnglish] = React.useState(0); // 2

  return (
    <div className='box'>
      <CourseList
        courses={courses}
        setAmountMust={setAmountMust}
      />
    </div>
  );
}
	
© www.soinside.com 2019 - 2024. All rights reserved.