简体   繁体   English

React不会更新作为props传递的组件的props

[英]React is not updating props of a component passed as props

I have a React DOM that looks like this: 我有一个React DOM看起来像这样:

DOM结构

In MarketDepthWindow 's state i have a isBackgroundEnabled which i want to pass as a props to the AskOrdersTab . MarketDepthWindow的状态下,我有一个isBackgroundEnabled ,我想将它作为道具传递给AskOrdersTab But it passes only the initial props and not updating. 但是它仅传递初始道具,而不更新。 It should update on MarketDepthHeaderComponent 's button click. 它应该在MarketDepthHeaderComponent的按钮单击上更新。

I assume that the problem is that i pass it as a prop to TabsContainer . 我认为问题是我将其作为道具传递给TabsContainer

I tried changing React.Component to React.PureComponent , using shouldComponentUpdate() , adding React.cloneElement and passing props through the TabsContainer but nothing works for me. 我试图改变React.ComponentReact.PureComponent ,使用shouldComponentUpdate()加入React.cloneElement并通过道具通过TabsContainer但没有为我工作。

Maybe I made some kind of architectural mistake? 也许我犯了某种建筑上的错误? Maybe i should use refs in some way? 也许我应该以某种方式使用裁判?

class AskOrdersTab extends React.Component {
  render() {
    return <div>bids</div>
  }
}

class BidOrdersTab extends React.Component {
  render() {
    return <div>asks</div>
  }
}

class MarketDepthHeaderComponent extends React.Component {
  render() {
    return <button class={this.props.isBackgroundEnabled ? 'active' : ''} onClick={this.props.handleBackgroundButtonClick}></button>
  }
}

class TabsContainer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      tabs: props.tabs.tabs || [],
      tabHeaderComponent: props.tabs.tabHeaderComponent || ''
    }
  }

  renderComponents() {
    let tabsComponents = [];
    for (let tab of this.state.tabs.length) {
      tabsComponents.push(
        <div>{tab.component}</div>
      )
    }
    return tabsComponents;
  }

  render() {
    return (
      <>
        {this.state.tabHeaderComponent}
        {this.renderComponents()}
      </>
    );
  }
}

class MarketDepthWindow extends React.Component {

  handleBackgroundButtonClick = (event) => {
    this.setState((prevState) => ({
      isBackgroundEnabled: !prevState.isBackgroundEnabled
    }))
  }

  constructor(props) {
    super(props)
    this.state = {
      isBackgroundEnabled: true,
      handleBackgroundButtonClick: this.handleBackgroundButtonClick
    }
  }

  render() {
    let tabsProps = {
      tabs: [
        { title: 'Bid', component: <BidOrdersTab {...this.state} /> },
        { title: 'Ask', component: <AskOrdersTab {...this.state} /> }
      ],
      tabHeaderComponent: <MarketDepthHeaderComponent {...this.state} />
    }
    return <TabsContainer tabs={tabsProps} isBackgroundEnabled={this.state.isBackgroundEnabled} />
  }
}

ReactDOM.render(
  <MarketDepthWindow />,
  document.getElementById("market-depth-window")
);

The simple answer to your question is that your storing AskOrdersTab in the state of TabsContainer , and in your case you want to access it via props. 简单的回答你的问题是,你的存储AskOrdersTab中的状态TabsContainer ,和你的情况要通过道具来访问它。

Explanation: What this has caused is whenever your component updates, which it is doing, TabsContainer will still render the original AskOrdersTab (this is due to the AskOrdersTab in state and the current version with updated props being the same object). 说明:这是由于组件更新而引起的, TabsContainer仍将呈现原始的AskOrdersTab (这是由于状态为AskOrdersTab且当前版本的更新道具是同一对象)。 There are ofcourse workarounds for this sort of behaviour using lifecycle hooks, namely getDerivedStateFromProps. 对于使用生命周期挂钩的这种行为,当然有变通办法,即getDerivedStateFromProps。 But in this case I wouldn't advise that. 但是在这种情况下,我不建议这样做。

TL;DR replace your TabsContainer with this one and it should work. TL; DR用这个替换您的TabsContainer ,它应该可以工作。

class TabsContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      tabHeaderComponent: props.tabs.tabHeaderComponent || '',
    };
  }

  renderComponents() {
    let tabsComponents = [];
    for (let tab of this.props.tabs.tabs) {
      tabsComponents.push(<div>{tab.component}</div>);
    }
    return tabsComponents;
  }

  render() {
    return (
      <>
        {this.state.tabHeaderComponent}
        {this.renderComponents()}
      </>
    );
  }
}

Finally, I think you're storing too much in state. 最后,我认为您存储的状态太多了。 Try importing components, or take a look at two common react patterns: 尝试导入组件,或者看看两种常见的反应模式:

  • Higher Order Components 高阶组件
  • Render Props 渲染道具

The state within TabsContainer is redundant, you should avoid storing state in each component as it cuts the update chain, Try using props instead. TabsContainer中的状态是多余的,应避免在每个组件中存储状态,因为它会切断更新链,请尝试使用props。

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

class AskOrdersTab extends React.Component {
  render() {
    return <div>bids</div>;
  }
}

class BidOrdersTab extends React.Component {
  render() {
    return <div>asks</div>;
  }
}

class MarketDepthHeaderComponent extends React.Component {
  render() {
    return (
      <button onClick={this.props.onClick}>
        {this.props.isBackgroundEnabled ? "enabled" : "disabled"}
      </button>
    );
  }
}

class TabsContainer extends React.Component {
  renderComponents() {
    let tabsComponents = [];
    for (let tab of this.props.tabs.tabs) {
      tabsComponents.push(<div key={tab.title}>{tab.component}</div>);
    }
    return tabsComponents;
  }

  render() {
    return (
      <>
        {this.props.tabs.tabHeaderComponent}
        {this.renderComponents()}
      </>
    );
  }
}

class MarketDepthWindow extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isBackgroundEnabled: true
    };
  }

  handleBackgroundButtonClick = () => {
    this.setState({
      isBackgroundEnabled: !this.state.isBackgroundEnabled
    });
  };

  render() {
    let tabsProps = {
      tabs: [
        { title: "Bid", component: <BidOrdersTab {...this.state} /> },
        { title: "Ask", component: <AskOrdersTab {...this.state} /> }
      ],
      tabHeaderComponent: (
        <MarketDepthHeaderComponent
          onClick={this.handleBackgroundButtonClick}
          isBackgroundEnabled={this.state.isBackgroundEnabled}
        />
      )
    };
    return (
      <TabsContainer
        tabs={tabsProps}
        isBackgroundEnabled={this.state.isBackgroundEnabled}
      />
    );
  }
}

const rootElement = document.getElementById("market-depth-window");
ReactDOM.render(<MarketDepthWindow />, rootElement);

This is your demo, you can check the fix and make sure it works. 这是您的演示,您可以检查此修复程序并确保其有效。 Good Luck 祝好运

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM