Кнопка Toogle не обновляет состояние должным образом - PullRequest
1 голос
/ 07 октября 2019

У меня есть кнопка, которую я использую для переключения боковой панели в приложении реакции. Кнопка переключения отлично работает для первых двух состояний переключения, затем дважды повторяет состояние в третий раз. Вот как я переключаю состояние с дочернего компонента на родительский:

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
    );
  }

}

Переключение кнопки отлично скрывает / открывает боковую панель, но она застревает в состоянии, когда получает значение «false» в два раза. Вот как работает консоль состояния:

enter image description here

Я не могу найти проблему здесь. Любая помощь приветствуется.

Ответы [ 4 ]

1 голос
/ 07 октября 2019

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

Это сработает для вас

0 голосов
/ 21 октября 2019

На мой взгляд, это может быть намного проще.

  1. Определить состояние родительского компонента App ìsToggled
  2. Вызов из заголовка дочернего компонента с помощью обратного вызова this.props.onToggle()
  3. Использовать условный рендеринг для родительского компонента {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>
        )
    }
}

0 голосов
/ 07 октября 2019

Вы должны вызвать getToggleState внутри вашего обратного вызова setState, чтобы использовать правильное состояние в качестве аргумента

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

Несмотря на это решение, лучше, если вы не сохраните дублирующее состояние в дочернем компоненте <Header /> как условноевизуализация является обязанностью родителей.

0 голосов
/ 07 октября 2019

Изменить эту часть кода:

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

На это:

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