2016-10-24 8 views
0

rief ich ma versucht, den Back-End-API aufrufen Profil des Benutzers beim Laden der Seite zu erhalten:ComponentWillMount wird immer wieder repeately

die folgende Aktion Gegeben:

export const GET_MY_PROFILE_START = 'GET_MY_PROFILE_START'; 
export const GET_MY_PROFILE_ERROR = 'GET_MY_PROFILE_ERROR'; 
export const GET_MY_PROFILE_SUCCESS = 'GET_MY_PROFILE_SUCCESS'; 

let a = 0; 
export function getMyProfile() { 
    a = a+1; 
    window.console.log("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); 
    window.console.log(a); 
    return dispatch => { 
    window.console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); 
     dispatch(getMyProfileStart()); 
    $.ajax({ 
      type: 'GET', 
      url: getMyProfileURL, 
      contentType: "application/json", 
      dataType: 'json', 
     }).done(function(res){ 
      if (!res.values || res.values.count > 0) { 
       dispatch(getMyProfileSuccess(res.data)) 
      } else { 
       dispatch(getMyProfileError()) 
      } 
     }).fail(function(error) { 
       dispatch(getMyProfileError()) 
     }) 
    } 
} 

function getMyProfileStart() { 
    return { 
     type: GET_MY_PROFILE_START, 
    } 
} 

function getMyProfileSuccess(profile) { 
    return { 
     type: GET_MY_PROFILE_SUCCESS, 
     profile: profile, 
    } 
} 

function getMyProfileError() { 
    return { 
     type: GET_MY_PROFILE_ERROR, 
    } 
} 

und folgende Minderer:

import { SET_USER_PROFILE, CLEAR_USER_PROFILE, GET_MY_PROFILE_START, GET_MY_PROFILE_ERROR, GET_MY_PROFILE_SUCCESS } from '../serActions' 

export default (state = { 
    loggedIn: false, 
    profiledLoading: false, 
    profile: {}, 
}, action) => { 
    switch (action.type) { 
     case SET_USER_PROFILE: 
      return { 
       loggedIn: true, 
       profiledLoading: false, 
       profile: {}, 
      } 
     case CLEAR_USER_PROFILE: 
      return { 
       loggedIn: false, 
       profiledLoading: false, 
       profile: {}, 
      } 
     case GET_MY_PROFILE_START: 
      return { 
       loggedIn: false, 
       profiledLoading: true, 
       profile: {}, 
      } 
     case GET_MY_PROFILE_ERROR: 
      return { 
       loggedIn: true, 
       profiledLoaded: false, 
       profile: {}, 
      } 
     case GET_MY_PROFILE_SUCCESS: 
      return { 
       loggedIn: true, 
       profiledLoading: false, 
       profile: action.profile, 
      } 
     default: 
      return state 
    } 
} 

und die folgende Komponente:

class AvatarButton extends Component { 
    componentWillMount() { 
     window.console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 
     this.props.dispatch(getMyProfile()) 
    } 

    render() { 
     //const { profile, toggleMenu, showHideMenu } = this.props 
     const { user } = this.props 
     window.console.log(user); 
     return (
      <a className="user-button nav-button avatar-button" 
       onClick={user.toggleMenu} 
       onBlur={this.hideMenu.bind(this)} 
      > 
       <i className="glyphicon glyphicon-user"/> 
      </a> 
     ) 
    } 

    hideMenu() { 
     this.props.user.showHideMenu(false) 
    } 
} 

AvatarButton.propTypes = { 
    toggleMenu: PropTypes.func.isRequired, 
    showHideMenu: PropTypes.func.isRequired, 
} 

function select(state) { 
    return { 
     user: state.user, 
    } 
} 

// Wrap the component to inject dispatch and state into it 
export default connect(select)(AvatarButton) 

Diese Komponente wird in verwendet:

class AppHandler extends Component { 
    componentWillMount() { 
     authUser(this.authSuccess.bind(this), this.authFail.bind(this)) 
    } 

    authSuccess() { 
     this.props.dispatch(login()) 
    } 

    authFail() { 
     this.props.dispatch(logout()) 
    } 

    render() { 
     window.console.log("renderrenderrenderrenderrenderrenderrenderrenderrenderrender"); 
     return (
      <div className="app-container"> 
      <div className="top-nav row"> 
       <div className="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12"> 
        <BackButton 
         pathname={this.props.location.pathname} 
        /> 
        <UserNavContainer 
         pathname={this.props.location.pathname} 
        /> 
        <div className="header"> 
         <img src="https://www.wewherego.com/img/logo/logo_wherego.png"/> 
         <h1>{this.props.pageHeader}</h1> 
        </div> 
       </div> 
      </div> 
      <ReactCSSTransitionGroup 
       transitionName="example" 
       transitionEnterTimeout={1000} 
       transitionLeaveTimeout={1000} 
      > 
       {React.cloneElement(this.props.children, { 
        key: this.props.location.pathname, 
       })} 
      </ReactCSSTransitionGroup> 
      </div> 
     ) 
    } 
} 

function select(state) { 
    return { 
     selectedCity: state.selectedCity, 
     pageHeader: state.pageHeader, 
    } 
} 

// Wrap the component to inject dispatch and state into it 
export default connect(select)(AppHandler) 

Im AppHandler, es ruft die folgenden Methoden in der ComponentWillMount:

class UserNavContainer extends Component { 
    constructor(props) { 
     super(props) 
     this.state = { 
      displayMenu: false, 
     } 
    } 
    render() { 
     const { dispatch, user, pathname } = this.props 
     if (!user.loggedIn) 
      return (
       <LoginButton pathname={pathname}/> 
      ) 

     return (
      <div className="user-nav"> 
       <AvatarButton 
        toggleMenu={this.toggleMenu.bind(this)} 
        showHideMenu={this.showHideMenu.bind(this)} 
       /> 
       <UserMenu 
        visible={this.state.displayMenu} 
        logoutHandler={this.logout.bind(this)} 
        hideMenu={this.showHideMenu.bind(this, false)} 
       /> 
      </div> 
     ) 
    } 

    logout() { 
     window.location = "some url" 
    } 

    toggleMenu() { 
     this.showHideMenu(!this.state.displayMenu) 
    } 

    showHideMenu(show) { 
     this.setState({ 
      displayMenu: show, 
     }) 
    } 
} 

function select(state) { 
    return { 
     user: state.user, 
    } 
} 

// Wrap the component to inject dispatch and state into it 
export default connect(select)(UserNavContainer) 

und schließlich die Top-Level-Komponente, die UserNavContainer verwendet

Exportfunktion authUser (loginCb, logoutCb) { const data = lesenCookie ('irgendwas')

if (!data) { 
    logoutCb() 
} else { 
    loginCb() 
} 
return 

}

Exportfunktion signoutUser() {// ein paar Sachen aufzuräumen }

Wenn ich die Seite am Öffnen, ich habe nur 1 Zeile von renderrenderrenderrenderrenderrenderrenderrenderrenderrenderrender

sehen kann, aber ich sehen Sie das Protokoll hält weiter Drucken:

UserNavContainerUserNavContainerUserNavContainerUserNavContainerUserNavContainerUserNavContainer 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
1057 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
1058 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
1059 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 

So appa Die componentWillMount-Methode wird aus irgendeinem Grund weiterhin aufgerufen, und das a in getMyProfile() geht jetzt zu 1059 (und zählt immer noch).

Ich habe keine Ahnung, warum das passieren würde?

+0

Ich denke, du solltest posten, wo du die Komponente auch renderst. Die Container-Komponente könnte ein Problem haben. –

+0

@BruceMu Ich habe mit mehr Details aktualisiert. – jamesdeath123

Antwort

0

Das eigentliche Problem ist, dass in den Komponenten, sie SET_USER_PROFILE Ereignis Disposition, die die LoggedIn Variable auf true ändert, dann aber die App entsendet GET_MY_PROFILE_START die Ändert die Variable loggedIn in false. Dies wiederum löst den neuen Zyklus aus und verschiebt lognIn auf true, so dass die Schleife weiterläuft.

Der richtige Weg, dies zu tun, ist, dass im Reducer anstelle von Variablen mit object.assign die Werte der Variablen geändert werden. So sollte es wirklich sein:

export default (state = { 
    loggedIn: false, 
    profiledLoading: false, 
    profile: {}, 
}, action) => { 
    switch (action.type) { 
     case GET_MY_PROFILE_START: 
      return Object.assign({}, state, { 
       loggedIn: true, 
       profiledLoading: true, 
      }) 
     case CLEAR_USER_PROFILE: 
      return Object.assign({}, state, { 
       loggedIn: false, 
      }) 
     case GET_MY_PROFILE_ERROR: 
      return Object.assign({}, state, { 
       profiledLoaded: false, 
       profile: {}, 
      }) 
     case GET_MY_PROFILE_SUCCESS: 
      return Object.assign({}, state, { 
       profiledLoading: false, 
       profile: action.profile, 
      }) 
     default: 
      return state 
    } 
} 
0

Wenn Sie Aktionen in Komponentenlebenszyklusmethoden senden, sollten Sie dies unter componentDidMount nicht willMount tun. Es scheint, dass Sie eine Endlosschleife auslösen, die das Montieren der Komponente blockiert.

+0

Ich versuchte mit ComponentDidMount, aber es gibt das gleiche Problem. – jamesdeath123

0

Versuchen durch Ihre onClick Funktionsaufruf Einwickeln as-

onClick={() => user.toggleMenu} 
Verwandte Themen