【问题标题】:REACT: Unable to update children props反应:无法更新儿童道具
【发布时间】:2025-11-28 09:35:01
【问题描述】:

我在更新标头类时遇到了麻烦,因此每当调用 displaySection() 时它都会更新它的 className。我知道父状态发生了变化,因为在 displaySection() 中完成的控制台日志注册了 this.state.headerVisible 更改,但我的子组件中没有任何更改,我不知道我错过了什么,我一直在尝试不同几个小时的解决方案,我只是无法弄清楚我做错了什么,标题 headerVisible 值保持为 TRUE 而不是在状态更改时更改。

我在控制台中没有收到任何错误代码,只是子 Header 中的 prop headerVisible 没有在其父状态更改时得到更新。

谢谢!

class IndexPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      section: "",
      headerVisible: true,

    }
    this.displaySection = this.displaySection.bind(this)
  }

  displaySection(sectionSelected) {
    this.setState({ section: sectionSelected }, () => {
      this.sectionRef.current.changeSection(this.state.section)
    })

    setTimeout(() => {
      this.setState({
        headerVisible: !this.state.headerVisible,
      })
    }, 325)

    setTimeout(()=>{
      console.log('this.state', this.state)
    },500)
  }

  render() {

    return (
      <Layout>
            <Header selectSection={this.displaySection} headerVisible={this.state.headerVisible} />
      </Layout>
    )
  }
}
const Header = props => (
  <header className={props.headerVisible ? 'visible' : 'invisible'}>
       <div className="navbar-item column is-size-7-mobile is-size-5-tablet is-uppercase has-text-weight-semibold">
              <span onClick={() => { this.props.selectSection("projects")}}>
                {" "}
                Projects
              </span>
  </header>
)

【问题讨论】:

  • 你如何验证类名没有改变? FWIW,如果您根据现有状态计算状态,请始终将函数传递给 setState: this.setState(state =&gt;({headerVisible: !state.headerVisible}))
  • 使用 Chrome 的 React 开发者工具,我可以看到 props 和 states 的变化。我看到 IndexPage 的状态发生了变化,但是 Header props 没有变化。
  • 你能提供一个minimal reproducible example吗?
  • 你永远不会调用 selectSection 函数。在返回页面内容之前为什么不尝试调用呢?
  • 是的,没错,试图简化问题的代码,但我忽略了它,我的错

标签: javascript reactjs


【解决方案1】:

您的示例代码似乎存在一些问题:

  1. 页眉中缺少结束 div
  2. 在 Header 的 span 中的 onclick 中使用 this.props 而不是 props

下面的最小示例似乎有效。我不得不删除您对 this.sectionRef.current.changeSection(this.state.section) 的电话,因为我不知道 sectionRef 应该是什么,因为它不在您的示例中。

class IndexPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      section: "",
      headerVisible: true,

    }
    this.displaySection = this.displaySection.bind(this)
  }

  displaySection(sectionSelected) {
    this.setState({ section: sectionSelected })

    setTimeout(() => {
      this.setState({
        headerVisible: !this.state.headerVisible,
      })
    }, 325)

    setTimeout(()=>{
      console.log('this.state', this.state)
    },500)
  }

  render() {

    return (
      <div>
            <Header selectSection={this.displaySection} headerVisible={this.state.headerVisible} />
      </div>
    )
  }
}

const Header = props => (
  <header className={props.headerVisible ? 'visible' : 'invisible'}>
       <div className="navbar-item column is-size-7-mobile is-size-5-tablet is-uppercase has-text-weight-semibold">
              <span onClick={() => { props.selectSection("projects")}}>
                {" "}
                Projects
              </span>
       </div>
  </header>
)

ReactDOM.render(
  <IndexPage />,
  document.getElementsByTagName('body')[0]
);
.visible {
  opacity: 1
}

.invisible {
  opacity: 0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

【讨论】:

    【解决方案2】:

    Header 组件中的代码中存在标记错误 - div 标记未关闭。 另外,我想,您删除了一些代码以简化示例,并且存在this.sectionRef.current.changeSection(this.state.section) 的工件,因为未定义this.sectionRef

    正如@Felix Kling 所说,当你根据之前的状态改变组件的状态时使用函数prevState =&gt; ({key: !prevState.key})

    这里的任何方式都是您尝试实现的工作示例:

    // @flow
    import * as React from "react";
    import Header from "./Header";
    
    type
    Properties = {};
    
    type
    State = {
        section: string,
        headerVisible: boolean,
    };
    
    class IndexPage extends React.Component<Properties, State> {
    
        static defaultProps = {};
    
        state = {};
    
        constructor(props) {
            super(props);
            this.state = {
                section: "",
                headerVisible: true,
    
            };
            this.displaySection = this.displaySection.bind(this)
        }
    
        displaySection(sectionSelected) {
            setTimeout(
                () => this.setState(
                    prevState => ({
                        section: sectionSelected,
                        headerVisible: !prevState.headerVisible
                    }),
                    () => console.log("Debug log: \n", this.state)
                ),
                325
            );
        }
    
        render(): React.Node {
            const {section, headerVisible} = this.state;
    
            return (
                <React.Fragment>
                    <Header selectSection={this.displaySection} headerVisible={headerVisible} />
                    <br/>
                    <div>{`IndexPage state: headerVisible - ${headerVisible} / section - ${section}`}</div>
                </React.Fragment>
            )
        }
    }
    
    export default IndexPage;
    

    和 Header 组件

    // @flow
    import * as React from "react";
    
    type Properties = {
        headerVisible: boolean,
        selectSection: (section: string) => void
    };
    
    const ComponentName = ({headerVisible, selectSection}: Properties): React.Node => {
        const headerRef = React.useRef(null);
    
        return (
            <React.Fragment>
                <header ref={headerRef} className={headerVisible ? 'visible' : 'invisible'}>
                    <div className="navbar-item column is-size-7-mobile is-size-5-tablet is-uppercase has-text-weight-semibold">
                        <span onClick={() => selectSection("projects")}>Projects</span>
                    </div>
                </header>
                <br/>
                <div>Header class name: {headerRef.current && headerRef.current.className}</div>
            </React.Fragment>
        );
    };
    
    export default ComponentName;
    

    【讨论】: