React 没有更新作为道具传递的组件的道具
React is not updating props of a component passed as props
我有一个 React DOM 看起来像这样:
在 MarketDepthWindow
的状态下,我有一个 isBackgroundEnabled
,我想将其作为道具传递给 AskOrdersTab
。但它只传递初始道具而不更新。它应该在 MarketDepthHeaderComponent
的按钮点击时更新。
我认为问题是我将它作为道具传递给 TabsContainer
。
我尝试将 React.Component
更改为 React.PureComponent
,使用 shouldComponentUpdate()
,添加 React.cloneElement
并通过 TabsContainer
传递道具,但对我来说没有任何效果。
也许我犯了某种架构错误?也许我应该以某种方式使用 refs?
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")
);
您的问题的简单答案是您将 AskOrdersTab
存储在 TabsContainer
的状态,并且在您的情况下您希望通过 props 访问它。
解释:这是什么原因造成的,每当你的组件更新时,它正在做,TabsContainer
仍然会呈现原始的 AskOrdersTab
(这是由于 AskOrdersTab
在状态和更新道具的当前版本是同一个对象)。对于使用生命周期挂钩的这种行为,当然有变通方法,即 getDerivedStateFromProps。但在这种情况下,我不建议这样做。
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()}
</>
);
}
}
最后,我认为您在状态中存储的太多了。尝试导入组件,或查看两种常见的 React 模式:
- 高阶组件
- 渲染道具
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);
这是您的演示,您可以检查修复并确保它有效。祝你好运
我有一个 React DOM 看起来像这样:
在 MarketDepthWindow
的状态下,我有一个 isBackgroundEnabled
,我想将其作为道具传递给 AskOrdersTab
。但它只传递初始道具而不更新。它应该在 MarketDepthHeaderComponent
的按钮点击时更新。
我认为问题是我将它作为道具传递给 TabsContainer
。
我尝试将 React.Component
更改为 React.PureComponent
,使用 shouldComponentUpdate()
,添加 React.cloneElement
并通过 TabsContainer
传递道具,但对我来说没有任何效果。
也许我犯了某种架构错误?也许我应该以某种方式使用 refs?
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")
);
您的问题的简单答案是您将 AskOrdersTab
存储在 TabsContainer
的状态,并且在您的情况下您希望通过 props 访问它。
解释:这是什么原因造成的,每当你的组件更新时,它正在做,TabsContainer
仍然会呈现原始的 AskOrdersTab
(这是由于 AskOrdersTab
在状态和更新道具的当前版本是同一个对象)。对于使用生命周期挂钩的这种行为,当然有变通方法,即 getDerivedStateFromProps。但在这种情况下,我不建议这样做。
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()}
</>
);
}
}
最后,我认为您在状态中存储的太多了。尝试导入组件,或查看两种常见的 React 模式:
- 高阶组件
- 渲染道具
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);
这是您的演示,您可以检查修复并确保它有效。祝你好运