当前位置: 首页 > 知识库问答 >
问题:

嵌套组件不更新其状态

乐正辰阳
2023-03-14

更新树结构中的嵌套组件时遇到问题。我创建了以下示例来说明这个问题:Codesandbox.io

为完整起见,这是正在嵌套的组件:

class Node extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selected: props.selected
    };
    this.toggleSelected = this.toggleSelected.bind(this);
  }

  toggleSelected() {
    this.setState({
      selected: !this.state.selected
    });
  }

  render() {
    return (
      <>
        <div onClick={this.toggleSelected}>
          Selected: {this.state.selected ? "T" : "F"}, Depth: {this.props.depth}
        </div>

        {this.props.depth < 5 && (
          <Node selected={this.state.selected} depth={this.props.depth + 1} />
        )}
      </>
    );
  }
}

树中的节点在单击时应该是可选择的,我还希望在所有子节点中(递归地)切换所选状态。我想我可以通过将this.state.selected通过道具传递给孩子们来实现这一点,不幸的是,这似乎不起作用。

但是,子对象使用其旧状态重新呈现(可以理解,因为它们没有通过构造函数重新初始化)。正确的处理方法是什么?

我还尝试将属性传递给节点,以帮助区分元素,但没有成功。

编辑:以下是一些理想行为的示例:

考虑一下这棵树:

[ ] Foo
    [ ] Foo A
        [ ] Foo A1
        [ ] Foo A2
    [ ] Foo B
        [ ] Foo B1
        [ ] Foo B2

检查"Foo"时的预期结果-节点:

[x] Foo
    [x] Foo A
        [x] Foo A1
        [x] Foo A2
    [x] Foo B
        [x] Foo B1
        [x] Foo B2

检查“Foo A”-节点时的预期结果:

[ ] Foo
    [x] Foo A
        [x] Foo A1
        [x] Foo A2
    [ ] Foo B
        [ ] Foo B1
        [ ] Foo B2

如有任何方向正确的提示,我们将不胜感激。

共有2个答案

孔城
2023-03-14

免责声明:我将演示如何在React应用程序中呈现树并管理其状态,而不是修复OP问题中的代码。

创建无状态的节点组件的数据驱动树并将状态管理留给根组件将更容易。

每个节点接收selectedId,并将其与自己的id进行比较,以了解它们(及其子节点)是否应呈现为活动状态。

他们还会收到一个setS选回调,以通知父节点他们被点击了。

由于受来自父级的数据(它们的唯一ID、选定状态等)的驱动,它变得更通用,并留下大量空间来使用新特性扩充树。它也是解耦的,更容易测试,等等。

// Stateless node
const Node = ({ depth, setSelected, selected, id, nodes, selectedId }) => {
  const isSelected = selected || selectedId === id;
  return (
    <React.Fragment>
      {id && (
        <div style={{ marginLeft: `${depth * 15}px` }}>
          <input
            type="checkbox"
            onChange={() => setSelected(id)}
            checked={isSelected}
          />
          {id}
        </div>
      )}

      {depth < 5 &&
        nodes.map(nodeProps => (
          <Node
            key={nodeProps.id}
            {...nodeProps}
            selected={isSelected}
            selectedId={selectedId}
            setSelected={setSelected}
            depth={depth + 1}
          />
        ))}
    </React.Fragment>
  );
};

Node.defaultProps = {
  selected: false,
  nodes: [],
  depth: 0
};

// Parent keeps the selected Id
class App extends React.Component {
  state = {
    selected: null
  };

  setSelected = id => {
    this.setState(({ selected }) => ({
      selected: selected !== id ? id : null
    }));
  };

  render() {
    return (
      <div className="App">
        <Node
          nodes={this.props.tree}
          selectedId={this.state.selected}
          setSelected={this.setSelected}
        />
      </div>
    );
  }
}

const treeData = [
  {
    id: "Foo",
    nodes: [
      {
        id: "Foo A",
        nodes: [{ id: "Foo A1" }, { id: "Foo A2" }]
      },
      {
        id: "Foo B",
        nodes: [{ id: "Foo B1" }, { id: "Foo B2" }]
      }
    ]
  }
];

ReactDOM.render(
  <App tree={treeData} />,
  document.getElementById("root")
);
input {
  cursor: pointer;
}
html prettyprint-override"><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>

澹台权
2023-03-14

你应该像这样使用getDerivedStateFromProps:

    constructor(props) {
       super(props);
       this.state = {
         selected: props.selected,
         propsSelected: props.selected
       };
       this.toggleSelected = this.toggleSelected.bind(this);
    }



    static getDerivedStateFromProps(props, state) {
        if (props.selected !== state.propsSelected)
          return {
            selected: props.selected,
            propsSelected: props.selected
          };
      }

我们总是将prevProp存储在状态中。每当我们遇到存储在状态中的道具和来自父级的道具发生变化时,我们都会更新从父级和组件本身控制的状态部分(selected),并且我们也会将道具保存在该状态,以备将来扩散。

通常,可以从父级和自身控制的组件将涉及此类逻辑。大多数react组件库中的输入组件就是一个理想的例子。

 类似资料:
  • 我正在尝试学习React(使用redux),所以我正在制作一个应用程序,在其中我可以创建训练计划,将训练添加到计划中,然后将训练添加到训练中。 PlanListComponent 我的PlansList组件为每个计划呈现一张卡片。在这张卡片中,它为该计划中的每个训练呈现一个训练列表。将训练添加到计划后,“计划列表”组件不会重新渲染。添加的训练仅在我刷新页面后显示。我之所以选择这种情况,是因为我必须

  • 问题内容: 所以,我有多个ReactComponent。最初,我以为会有一个带有其自身状态的父组件(简称为GrandPa),它将有关其状态的一些信息传递给另一个组件(称为Parent)。同样,父母将他的一些财产传给孩子,孩子则传给孙子。因此,我们具有层次结构: 爷爷->父母->孩子->孙子 但是,我很快意识到,当我使用method 更改GrandPa的状态时,所做的更改不会沿通道向下级联。我意识到

  • 我正在尝试更新嵌套数组中的值,但无法使其工作。 我的对象是这样的 提前谢谢!

  • 问题内容: 添加评论时,我试图使angular.js视图本身进行更新。我的代码如下: 范围在输入时更新: 调试$ scope.currentItem显示注释已添加到其中,但是视图未显示新注释。我怀疑$ scope仅在其第一级被监视,这就是为什么视图不更新的原因。是这样吗?如果可以,我该如何解决? 解决方案:正如Ajay在下面的回答中所建议的那样,我将数组推入包装为apply函数,如下所示: 问题答

  • 我正在使用平均堆栈在网格中显示以下数组。 嵌套数组:

  • 问题内容: 我正在尝试更新嵌套数组中的值,但无法使其正常工作。 我的对象是这样的 我需要将值推送到“ answeredBy”数组。 在下面的示例中,我尝试将“成功”字符串推到“ 123 _id”对象的“ answeredBy”数组中,但是它不起作用。 我找到了此链接,但其答案仅表示我应该使用类似结构的对象而不是数组。这不适用于我的情况。我真的需要将我的对象嵌套在数组中 如果您能在这里帮助我,那就太