2017-02-11 4 views
1

У меня возникла проблема с компонентом рендеринга, когда родительское состояние передано дочерним компонентам. Компонент MapNav содержит кнопки, которые запускают методы, изменяющие текущее всплывающее окно. Моя проблема заключается в кнопке UserPopup повторной визуализации, когда кто-то нажимает zaloguj или wyloguj, он должен работать, но это не делает, и я не могу понять, что это неправильно и я не хочу, чтобы вызвать анимацию при isLoggedIn изменения состояния и еще одна вещь метод logIn изменяет состояние должным образом. isLoggedIn Состояние только временно. Я изменю это, чтобы вместо этого использовать хранилище. Я пытаюсь написать столько функционального компонента, но в некоторых случаях я не могу избежать использования состояния, и я уверен, что в моем коде есть проблемы, поэтому я буду признателен за все советы по улучшению.Функциональный компонент Rerender при изменении prop

const MapNav = (props) => { 
 
    return  <div className={'mapNavContainer'}> 
 
     <ul className={'navList'}> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-fullscreen"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-chevron-left"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-chevron-right"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-map-marker"} /></a></li> 
 
      <li><a href="#" onClick={props.onUserIconClick}><i className={"glyphicon glyphicon-user"} /></a></li> 
 
      <li><a href="#" onClick={props.onInfoClick}><i className={"glyphicon glyphicon-info-sign"} /></a></li> 
 
     </ul> 
 
     </div> 
 
} 
 

 
const UserPopup = (props) => { 
 
    return <div> 
 
    {(props.isLoggedIn) ? (
 
     <div className={'navPopups col-sm-3 panel panel-default'}> 
 
     <div className={"panel-heading"}>Zalogowany</div> 
 
     <div className={"panel-body"}> 
 
      <button type='submit' onClick={props.logIn}>wyloguj</button> 
 
     </div> 
 
     </div> 
 
    ) : (
 
     <div className={'navPopups col-sm-3 panel panel-default'}> 
 
      <div className={"panel-heading"}>Niezalogowany</div> 
 
      <div className={"panel-body"}> 
 
      <button type='submit' onClick={props.logIn}>Zaloguj</button> 
 
      </div> 
 
     </div> 
 
    ) 
 
    } 
 
    </div>; 
 
}; 
 

 
function Welcome(props) { 
 
    return <div className={'navPopups col-sm-3 panel panel-default'}> 
 
    <div className={"panel-heading"}>Informacje o Autorze.</div> 
 
    <div className={"panel-body"}> 
 
     Basic panel example 
 
    </div> 
 
    </div>; 
 
} 
 

 
class MapHeader extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     currentPopup: null, 
 
     isLoggedIn: false, 
 
     username: '[email protected]', 
 
    }; 
 

 
    this.onInfoClick = this.onInfoClick.bind(this); 
 
    this.onUserIconClick = this.onUserIconClick.bind(this); 
 
    this.logIn = this.logIn.bind(this); 
 
    } 
 

 
    onInfoClick = (e) => { 
 
    e.preventDefault(); 
 
    this.setPopup(<Welcome />); 
 
    } 
 

 
    onUserIconClick = (e) => { 
 
    e.preventDefault(); 
 
    const loginPopup = <UserPopup isLoggedIn={this.state.isLoggedIn} username={this.state.username} logIn={this.logIn} />; 
 
    this.setPopup(loginPopup); 
 
    } 
 

 
    setPopup = (obj) => { 
 
    this.state.currentPopup === null ? this.setState({ currentPopup: obj }) : this.setState({ currentPopup: null }); 
 
    } 
 

 
    logIn = (e) => { 
 
    this.setState({ isLoggedIn: !this.state.isLoggedIn }); 
 
    } 
 

 
    render() { 
 
    return (
 
     <nav className={'header'}> 
 
     <div className={'container-fluid'}> 
 
      <div className={"navbar-header"}> 
 
      <button type="button" className={"navbar-toggle collapsed"} data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 
 
       <span className={"sr-only"}>Toggle navigation</span> 
 
       <span className={"icon-bar"} /> 
 
       <span className={"icon-bar"} /> 
 
       <span className={"icon-bar"} /> 
 
      </button> 
 
      </div> 
 

 
      <div id={"navbar"} className={'navContainer'}> 
 
      {MapNav({onInfoClick:this.onInfoClick, onUserIconClick:this.onUserIconClick})} 
 
    {this.state.currentPopup ? this.state.currentPopup : null} 
 
      </div> 
 
     </div> 
 
     </nav> 
 
    ) 
 
    } 
 
} 
 

 
// Render it 
 
ReactDOM.render(
 
    <MapHeader />, 
 
    document.getElementById("react") 
 
);
<div id="react"></div> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />

+2

Side Примечание: 'имя класса = { "панель-заголовок"}' можно более просто записать '= имя класса "панель-заголовок"'. Нет необходимости в '{}', когда значение является простой строкой. –

+0

Благодарим вас за отзыв и добавили runnable – habibi07

+1

Боковое примечание 2: Ваш 'logIn' и такие функции стрелок, которые закрываются над' this'. Вызов 'bind' на них не будет делать ничего, чтобы изменить их' this' (но это уже правильно, поэтому вам не нужно 'bind'). –

ответ

0

Я решил. В моем коде есть текущее состояниеPopup, которое хранило текущее всплывающее окно, чтобы увидеть изменения, которые мне пришлось отключить и снова смонтировать компонент после изменения состояния isLogggedIn, поэтому я изменил способ отображения текущего всплывающего окна. Вместо хранения всего компонента в состоянии я храню только простые строковые значения, которые предоставляют информацию о текущем компоненте. В любом случае, спасибо за советы, я обязательно применим их в своем коде.

const MapNav = (props) => { 
 
    return  <div className={'mapNavContainer'}> 
 
     <ul className={'navList'}> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-fullscreen"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-chevron-left"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-chevron-right"} /></a></li> 
 
      <li><a href="#about"><i className={"glyphicon glyphicon-map-marker"} /></a></li> 
 
      <li><a href="#" onClick={props.onUserIconClick}><i className={"glyphicon glyphicon-user"} /></a></li> 
 
      <li><a href="#" onClick={props.onInfoClick}><i className={"glyphicon glyphicon-info-sign"} /></a></li> 
 
     </ul> 
 
     </div> 
 
} 
 

 
const UserPopup = (props) => { 
 
    return <div> 
 
    {(props.isLoggedIn) ? (
 
     <div className={'navPopups col-sm-3 panel panel-default'}> 
 
     <div className={"panel-heading"}>Zalogowany</div> 
 
     <div className={"panel-body"}> 
 
      <button type='submit' onClick={props.logIn}>wyloguj</button> 
 
     </div> 
 
     </div> 
 
    ) : (
 
     <div className={'navPopups col-sm-3 panel panel-default'}> 
 
      <div className={"panel-heading"}>Niezalogowany</div> 
 
      <div className={"panel-body"}> 
 
      <button type='submit' onClick={props.logIn}>Zaloguj</button> 
 
      </div> 
 
     </div> 
 
    ) 
 
    } 
 
    </div>; 
 
}; 
 

 
function Welcome(props) { 
 
    return <div className={'navPopups col-sm-3 panel panel-default'}> 
 
    <div className={"panel-heading"}>Informacje o Autorze.</div> 
 
    <div className={"panel-body"}> 
 
     Basic panel example 
 
    </div> 
 
    </div>; 
 
} 
 

 
class MapHeader extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     currentPopup: null, 
 
     isLoggedIn: null, 
 
    }; 
 

 
    this.onInfoClick = this.onInfoClick.bind(this); 
 
    this.onUserIconClick = this.onUserIconClick.bind(this); 
 
    this.logIn = this.logIn.bind(this); 
 
    } 
 
        
 
    onInfoClick = (e) => { 
 
    e.preventDefault(); 
 
    this.setState({ currentPopup: this.state.currentPopup === 'info' ? null : 'info' }); 
 
    } 
 
    
 
    onUserIconClick = (e) => { 
 
    e.preventDefault(); 
 
    this.setState({ currentPopup: this.state.currentPopup === 'user_login' ? null : 'user_login' }); 
 
    } 
 

 
    setPopup = (obj) => { 
 
    this.setState({ currentPopup: this.state.currentPopup === 'user_login' ? null : 'user_login' }); 
 
    } 
 

 
    logIn = (e) => { 
 
    this.setState({ isLoggedIn: !this.state.isLoggedIn }); 
 
    } 
 

 
    render() { 
 
    return (
 
     <nav className={'header'}> 
 
     <div className={'container-fluid'}> 
 
      <div className={"navbar-header"}> 
 
      <button type="button" className={"navbar-toggle collapsed"} data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 
 
       <span className={"sr-only"}>Toggle navigation</span> 
 
       <span className={"icon-bar"} /> 
 
       <span className={"icon-bar"} /> 
 
       <span className={"icon-bar"} /> 
 
      </button> 
 
      </div> 
 

 
      <div id={"navbar"} className={'navContainer'}> 
 
      {MapNav({onInfoClick:this.onInfoClick, onUserIconClick:this.onUserIconClick})} 
 

 
       {this.state.currentPopup === 'info' ? <Welcome /> : null} 
 
       {this.state.currentPopup === 'user_login' ? (
 
       <UserPopup isLoggedIn={this.state.isLoggedIn} logIn={this.logIn} /> 
 
      ) : null} 
 

 
      </div> 
 
     </div> 
 
     </nav> 
 
    ) 
 
    } 
 
} 
 

 
// Render it 
 
ReactDOM.render(
 
    <MapHeader />, 
 
    document.getElementById("react") 
 
);
<div id="react"></div> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />

Смежные вопросы