父状态更改后,ReactJs子级未更新

时间:2019-11-21 23:10:37

标签: reactjs jsx

我正在尝试使用ReactJS构建一个动态组件。因此,我有一个产品列表,每当用户想要添加新产品时,他都会单击+按钮。这将创建一个新产品并将其添加到列表中。列表中有一个名为delete all的按钮,用于删除所有产品。

要删除所有产品,我在产品列表中使用了一个在组件创建时使用“创建”初始化的状态,当用户单击“全部删除”时,我将其更改为“已删除”以使用ComponentWillUpdate更新子项(产品)回调。

这是一些代码:

index.js

render() {
    return (
      <div className="App">
        <h1>Dynamic List</h1>
        <ProductList />
        <hr />
        <h1>Static List</h1>
        <ProductListStatic />
      </div>
    );
  }

Product.js

class Product extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      state: "created"
    };
  }

  componentDidUpdate(prevProps) {
    if (
      this.props.parentState === "deleted" &&
      this.state.state === "created"
    ) {
      this.setState({ state: "deleted" });
    }
  }

  render() {
    if (this.state.state !== "deleted") {
      return (
        <div style={{ margin: "5px" }}>
          Product.....
          <button onClick={this.props.addNewProduct}>+</button>
        </div>
      );
    } else {
      return null;
    }
  }
}

我的ProductList.js

class ProductList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [],
      state: "created"
    };
  }

  componentDidMount() {
    let newProducts = [...this.state.products];
    newProducts.push(
      <Product
        key={0}
        addNewProduct={this.addNewProduct}
        parentState={this.state.state}
      />
    );
    this.setState({ products: newProducts });
  }

  addNewProduct = () => {
    let length = this.state.products.length;
    const newProducts = [
      ...this.state.products,
      <Product
        key={length}
        addNewProduct={this.addNewProduct}
        parentState={this.state.state}
      />
    ];
    this.setState({ products: newProducts });
  };

  deleteAll = () => {
    this.setState({ state: "deleted" });
  };

  render() {
    return (
      <div>
        {this.state.products}
        <button style={{ marginTop: "20px" }} onClick={this.deleteAll}>
          Delete All
        </button>
      </div>
    );
  }
}

这不会更新孩子,我也不知道为什么。我认为这是因为清单是动态的。我尝试使用静态列表进行尝试,并且效果很好(下面的代码)。

ProductListStatic.js

class ProductListStatic extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [],
      state: "created"
    };
  }

  deleteAll = () => {
    console.log("delete all");
    this.setState({ state: "deleted" });
  };

  render() {
    let products = [
      <Product
        key={0}
        addNewProduct={this.addNewProduct}
        parentState={this.state.state}
      />,
      <Product
        key={1}
        addNewProduct={this.addNewProduct}
        parentState={this.state.state}
      />
    ];
    return (
      <div>
        {products}
        <button style={{ marginTop: "20px" }} onClick={this.deleteAll}>
          Delete All
        </button>
      </div>
    );
  }
}

这是一个演示:SandBox live dome

任何人都知道为什么它不能与动态产品一起使用吗?

1 个答案:

答案 0 :(得分:2)

问题在于状态数组中的JSX元素不知道在父级重新渲染时需要重新渲染它们。在静态版本中,子代直接在JSX中创建,因此重新渲染的行为是正常的。合理的解决方案是在子状态数组中存储子项的数据,然后通过在每个渲染器上在该状态数组上调用construct来创建子项。

除此之外,整体设计似乎不必要地复杂。我认为孩子//ADD LINE BREAK add_filter( 'the_title', 'custom_the_title', 10, 2 ); function custom_the_title( $title, $post_id ) { $post_type = get_post_field( 'post_type', $post_id, true ); if( $post_type == 'product' || $post_type == 'product_variation' ) $title = str_replace( '|', '<br/>', $title ); // we replace '|' by '<br>' return $title; } 不必担心何时渲染,或者是否应该通过孩子的回调将产品添加到父亲中。将所有这些信息保留在父级中要简单得多。渲染可能是隐式的-如果我们想要一个新商品,请将其推到product / items数组中,如果我们想清除所有商品,请将数组设置为.map。不需要Product

这是一个概念证明:

[]
this.state.state

如果您计划为每种产品添加其他按钮和数据,则可能需要一个行容器。然后,当行应将更改应用于项目时,回调将成为行向父母发出信号的必要条件。这取决于您的设计目标,目前还为时过早(从const mockProduct = () => ({ name: [ "apple", "banana", "cherry", "kiwi", "watermelon", "pineapple", "blueberry" ][~~(Math.random()*7)], price: ~~(Math.random() * 5) + 0.99 }); const Product = props => <div> <span>{props.name}</span> <span>{props.price}</span> </div> ; class Products extends React.Component { constructor(props) { super(props); this.state = {products: [mockProduct()]}; this.addNewProduct = this.addNewProduct.bind(this); this.deleteAll = this.deleteAll.bind(this); } addNewProduct() { this.setState({ products: this.state.products.concat(mockProduct()) }); } deleteAll() { this.setState({products: []}); } render() { return ( <React.Fragment> <div> {this.state.products.map((e, i) => <div style={{display: "flex"}} key={`${i}-${e.name}`} > <Product name={e.name} price={e.price} /> <button onClick={this.addNewProduct}>+</button> </div> )} </div> <div> <button onClick={this.deleteAll}>delete all</button> </div> </React.Fragment> ); } } ReactDOM.render(<Products />, document.body);除去渲染问题之后,没有太多理由证明其存在。)