道具变更时,React子组件不会重新渲染

时间:2020-01-15 06:20:18

标签: javascript html css reactjs

我正在尝试创建一个嵌套/分组复选框的列表,在其中选择一个复选框(父级)应基于数据对象数组选择其他复选框(所有子级)。现在,以checked状态对App.js值进行硬编码会反映复选框的输出滴答声,但是当通过将setState作为道具传递给子组件来修改状态时,复选框不更新。

一种部分解决我想做的事情的怪诞方法是通过在useState的onChange方法中使用CheckBoxGroup.js来更改布尔值,从而迫使组件进行更新。但是即使那样,控制台仍会显示正确的更改的props.state,但是app.js组件的状态不会反映出来。没有useState,复选框似乎也不会重新呈现。有人可以帮忙吗? 谢谢

以下是代码。 此处的代码沙箱链接:https://codesandbox.io/s/red-haze-ij1km?fontsize=14&hidenavigation=1&theme=dark

App.js

import React, { useState } from "react";
import "./styles.css";
import FoodGroup from "./FoodGroup";

export default function App() {
  let arr = [
    {
      name: "Fruits",
      parentId: 100,
      data: [{ value: "Apple", id: 1 }, { value: "Banana", id: 2 }]
    },
    {
      name: "Vegetables",
      parentId: 200,
      data: [{ value: "Potato", id: 3 }, { value: "Onion", id: 4 }]
    }
  ];
  const [state, setState] = useState({
    // basically selecting all id : { selected : true } for parent id and child id
    1: { selected: false },
    2: { selected: false },
    100: { selected: false }
  });

  return (
    <div className="App">
      <FoodGroup data={arr} state={state} setState={setState} />
    </div>
  );
}

FoodGroup.js

import React from "react";
import CheckBoxGroup from "./CheckBoxGroup";

const FoodGroup = props => {
  let groups = props.data.map((group, index) => (
    <CheckBoxGroup
      group={group}
      key={index}
      data={props.data}
      setState={props.setState}
      state={props.state}
    />
  ));
  return <ul>{groups}</ul>;
};

export default FoodGroup;

CheckBoxGroup.js

import React, { useState } from "react";
import CheckBox from "./CheckBox";

const CheckBoxGroup = props => {
  // const [a, b] = useState(false);
  const onChildChange = (child, e) => {
    let childSelected = props.state;
    if (!childSelected[child]) {
      childSelected[child] = {};
    }
    childSelected[child].selected = e.target.checked;
    props.setState(childSelected);
    // b(!a); a hacky way I found a work around to force re render the component otherwise it doesn't
    // work
  };

  const onParentChange = (child, e) => {
    let childSelected = props.state;
    if (!childSelected[child]) {
      childSelected[child] = {};
    }
    let childInThatParent = [];
    props.data.forEach(group => {
      if (group.parentId === child) {
        group.data.forEach(item => {
          childInThatParent.push(item.id);
        });
      }
    });
    childSelected[child].selected = e.target.checked;

    childInThatParent.forEach(child => {
      if (!childSelected[child]) {
        childSelected[child] = {};
      }
      childSelected[child].selected = e.target.checked;
    });

    props.setState(childSelected);
    // b(!a);
  };

  let checkboxes = props.group.data.map((item, index) => (
    <CheckBox
      onChange={onChildChange}
      value={item.value}
      id={item.id}
      key={item.id}
      setState={props.setState}
      state={props.state}
    />
  ));

  return (
    <React.Fragment>
      <CheckBox
        onChange={onParentChange}
        value={props.group.name}
        id={props.group.parentId}
        countrySelected={props.state}
        setState={props.setState}
        state={props.state}
      />
      <ul>{checkboxes}</ul>
    </React.Fragment>
  );
};

export default CheckBoxGroup;

CheckBox.js

import React, { useState } from "react";

const CheckBox = ({ state, id, onChange, value }) => {
  return (
    <li>
      <input
        type="checkbox"
        value={id}
        onChange={e => {
          onChange(id, e);
        }}
        checked={state[id].selected}
      />
      {value}
    </li>
  );
};

export default CheckBox;

1 个答案:

答案 0 :(得分:1)

在用onChildChangeonParentChange方法更新状态时,您引用的是同一状态。您可以检查沙箱进行修复:https://codesandbox.io/s/loving-moon-0e91c

检查CheckBoxGroup.js文件中的onChildChangeonParentChange方法