切换按钮未正确更新状态

Toogle button not updating state properly

我有一个按钮,用于在 React 应用程序中切换侧边栏。切换按钮在前两个切换状态下工作正常,而不是第三次重复该状态两次。 这就是我将状态从子组件切换到父组件的方式:

import React, { Component } from 'react'

export default class Header extends Component {
    constructor(props) {
        super(props)

        this.state = {
             toggle: false
        }
    }

    toggleSidebar = () => {

        this.setState({
            toggle : !this.state.toggle
        });
        console.log(this.state.toggle)
        this.props.getToggleState(this.state.toggle);
    }

    render() {
        return (
            <div>
                 <button style={{width: '60px'}} onClick={this.toggleSidebar}>Toogle</button>
            </div>
        )
    }
}



export default class App extends Component{

  constructor(props) {
    super(props)

    this.state = {
      toggleVal:''
    }
  }

  getData = (val) => {
   this.setState({
     toggleVal: val
   })
}

  render(){
    let toggleConst = '';
    if(this.state.toggleVal){
      toggleConst = (
                <Router>
                <div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
                  <div style={{flexDirection:'column'}}>
                    <Header getToggleState={this.getData}/>
                      <Routes/>
                    <Footer/>
                  </div>
                </div>
              </Router>
      )
    }
    else{
      toggleConst = (
                <Router>
                <div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
                  <SideNav toggleVal={this.state.toggleVal}/>
                  <div style={{flexDirection:'column'}}>
                    <Header getToggleState={this.getData}/>
                      <Routes/>
                    <Footer/>
                  </div>

                </div>
              </Router>
      )
    }
    return (
      toggleConst
    );
  }

}

完美地切换按钮 hides/open 侧边栏,但它在获得 'false' 两次时卡在状态。 这是状态控制台的运行方式:

我在这里找不到问题。任何帮助表示赞赏。

App.js

import React, {Component} from 'react';
import { BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'

export default class App extends Component{

  constructor(props) {
    super(props)
  
    this.state = {
      toggleVal: false
    }
  }
  
  getData = (val) => {
   
   this.setState({
     toggleVal: val
   });
}

  render(){
    console.log("called.....123...",this.state.toggleVal)
    if(this.state.toggleVal){
      return (
                <Router>
                <div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
                <Sidebar toggleVal={this.state.toggleVal}/>
                  <div style={{flexDirection:'column'}}>
                    <Header getToggleState={this.getData} />
                  </div>
                </div>
              </Router>
      )
    }
    else{
      return (
                <Router>
                <div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
                  <Sidebar toggleVal={this.state.toggleVal}/>
                  <div style={{flexDirection:'column'}}>
                    <Header getToggleState={this.getData}/>

                  </div>
                </div>
              </Router>
      )
    }
  }
  
}

Header.js

import React, { Component } from 'react'

export default class Header extends Component {
    constructor(props) {
        super(props)
    
        this.state = {
             toggle: false
        }
    }


    toggleSidebar = () => {

        this.setState({
          toggle: !this.state.toggle
        },()=>{
            // console.log(this.state.toggle)
            this.props.getToggleState(this.state.toggle);
        });
       
    }
    
    render() {
        return (
            <div>
                 <button onClick={()=>this.toggleSidebar(this.state.toggle)}>Toogle</button>
            </div>
        )
    }
}

Sidebar.js

import React, { Component } from 'react'
import { NavLink } from "react-router-dom";


export default class Sidebar extends Component {
    render() {
        return (
            <>
            {
                this.props.toggleVal &&
                    <div className="sidebar_container">
                        <nav className="nav_container">
                            <ul>
                                <li>
                                    <NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
                                </li>
                                <li>
                                    <NavLink to="/user" activeClassName="active">User PRofile</NavLink>
                                </li>
                                <li>
                                    <NavLink to="/register" activeClassName="active">Register</NavLink>
                                </li>
                            </ul>
                        </nav>
                    </div>
            }
            </>
        )
    }
}

https://repl.it/repls/IncredibleLinedCgi

这对你有用

更改这部分代码:

this.setState({
        toggle : !this.state.toggle
    });

为此:

this.setState(prev => {
        return { toggle : !prev.toggle }
    });

您应该在 setState 回调中调用 getToggleState 以使用正确的状态作为参数

this.setState(prevState => {
  this.props.getToggleState(!prevState.toggle);
  return { toggle: !prevState.toggle };
});

尽管有这个解决方案,但最好不要在子组件中保留重复状态 <Header />,因为条件渲染是父组件的职责。

我认为这可以简单得多。

  1. Define the state on the parent component App ìsToggled
  2. Call from the child component Header via callback this.props.onToggle()
  3. Use conditional rendering on parent component {this.state.isToggled && <Sidebar/>}
import React, {Component} from 'react';
import {BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'

export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isToggled: false
        }
    };

    onToggle = () => {
        this.setState({
            isToggled: !this.state.isToggled
        });
        console.log(this.state.isToggled);
    };

    render() {
        return (
            <Router>
                <div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection: 'row'}}>
                    <div style={{flexDirection: 'column'}}>
                        <Header onToggle={this.onToggle}/>
                    </div>
                    {this.state.isToggled && <Sidebar/>}
                </div>
            </Router>
        )
    }
}
import React, {Component} from 'react'

export default class Header extends Component {
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <div>
                <button onClick={() => {
                    this.props.onToggle()
                }}>Toggle
                </button>
            </div>
        )
    }
}
import React, {Component} from 'react'
import {NavLink} from "react-router-dom";

export default class Sidebar extends Component {
    render() {
        return (
            <div className="sidebar_container">
                <nav className="nav_container">
                    <ul>
                        <li>
                            <NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
                        </li>
                        <li>
                            <NavLink to="/user" activeClassName="active">User PRofile</NavLink>
                        </li>
                        <li>
                            <NavLink to="/register" activeClassName="active">Register</NavLink>
                        </li>
                    </ul>
                </nav>
            </div>
        )
    }
}