web-dev-qa-db-fra.com

React history.Push () ne rend pas le nouveau composant

Bonjour à tous!

J'ai un projet React.js avec une fonction de connexion simple. Une fois l'utilisateur autorisé, j'appelle la méthode history.Push qui modifie le lien dans la barre d'adresse mais ne rend pas le nouveau composant. (J'utilise BrowserRouter)

Mon index.js composant:

ReactDOM.render(
  <Provider store={createStore(mainReducer, applyMiddleware(thunk))}>
    <BrowserRouter>
      <Main />
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);

Mon Main.js composant:

const Main = (props) => {
  return (
    <Switch>
      <Route exact path="/" component={Signin} />
      <Route exact path="/servers" component={Servers} />
    </Switch>
)}

export default withRouter(Main);

Mon Créateur d'action:

export const authorization = (username, password) => (dispatch) =>
  new Promise ((resolve, reject) => {
    fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: username,
        password: password,
      })
    }).then( response => {
      if (response.ok) {
          response.json().then( result => {
            console.log("API reached.");
            dispatch(logUserIn(result.token));
            resolve(result);
        })
      } else {
        let error = new Error(response.statusText)
        error.response = response
        dispatch(showError(error.response.statusText), () => {throw error})
        reject(error);
      }
    });
  });

Mon Signin.js composant:

 handleSubmit(event) {

    event.preventDefault();

    this.setState({ isLoading: true })

    const { username, password } = this.state;
    this.props.onLoginRequest(username, password, this.props.history).then(result => {
      console.log("Success. Token: "+result.token); //I do get "success" in console
      this.props.history.Push('/servers') //Changes address, does not render /servers component
    });

  }

const mapActionsToProps = {
  onLoginRequest: authorization
}

Le plus étrange est que si je change ma méthode handleSubmit () en ceci - tout fonctionne parfaitement:

  handleSubmit(event) {

    event.preventDefault();

    this.setState({ isLoading: true })

    const { username, password } = this.state;
    this.props.onLoginRequest(username, password, this.props.history).then(result => {
      console.log("Success. Token: "+result.token);
      //this.props.history.Push('/servers')
    });
    this.props.history.Push('/servers')
  }

Le même problème survient si j'essaie de transmettre l'historique à partir de la méthode componentWillReceiveProps (newProps) - il change d'adresse mais ne rend pas le nouveau composant. Quelqu'un pourrait-il expliquer pourquoi cela se produit et comment y remédier?

Je vous remercie!

6
zilijonas

Si quelqu'un est intéressé - cela se produisait parce que l'application était en cours de rendu avant que l'historique ne soit poussé. Lorsque j'ai mis l'historique Push dans mon action, mais juste avant que le résultat ne soit converti en JSON, il a commencé à fonctionner, car maintenant il pousse l'historique et ne rend que l'application.

export const authorization = (username, password, history) => (dispatch) =>
  new Promise ((resolve, reject) => {
    fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: username,
        password: password,
      })
    }).then( response => {
      if (response.ok) {

          //################################
          //This is where I put it

          history.Push("/servers");

          //################################

          response.json().then( result => {
            dispatch(logUserIn(result.token));
            resolve(result);
        })
      } else {
        let error = new Error(response.statusText)
        error.response = response
        dispatch(showError(error.response.statusText), () => {throw error})
        reject(error);
      }
    });
  });
3
LiJonas

Ne fonctionne pas sur celui-ci ->

handleSubmit(event) {

    event.preventDefault();

    this.setState({ isLoading: true })

    const { username, password } = this.state;
    this.props.onLoginRequest(username, password, this.props.history).then(result => {
      console.log("Success. Token: "+result.token); //I do get "success" in console
      this.props.history.Push('/servers') //Changes address, does not render /servers component
    });

  }

const mapActionsToProps = {
  onLoginRequest: authorization
}

Dans cette méthode handleSubmit, vous appelez this.props.history.Push () à l'intérieur d'une promesse afin que this pointe vers l'instance de Promise et non vers votre instance de classe actuelle.

Essayez celui-ci ->

 handleSubmit(event) {

    event.preventDefault();
    const { history: { Push } } = this.props;
    this.setState({ isLoading: true })

    const { username, password } = this.state;
    this.props.onLoginRequest(username, password, this.props.history).then(result => {
      console.log("Success. Token: "+result.token); //I do get "success" in console
      Push('/servers') //Changes address, does not render /servers component
    });
  }

const mapActionsToProps = {
  onLoginRequest: authorization
}

Maintenant dans cette déclaration ->

 handleSubmit(event) {

    event.preventDefault();

    this.setState({ isLoading: true })

    const { username, password } = this.state;
    this.props.onLoginRequest(username, password, this.props.history).then(result => {
      console.log("Success. Token: "+result.token);
      //this.props.history.Push('/servers')
    });
    this.props.history.Push('/servers')
  }

Vous appelez correctement this.props.history.Push () car il est hors de la promesse et fait référence à l'instance Current Class.

0
Harish Soni

Essayez d'utiliser l'historique personnalisé et le routeur au lieu de BrowserRouter. Après l'installation de l'historique:

yarn add history

Créez un historique de navigateur personnalisé:

import { createBrowserHistory } from "history";

export default createBrowserHistory();

Utilisez Router au lieu de BrowserRouter dans votre configuration:

import history from "your_history_file";

ReactDOM.render(
  <Provider store={createStore(mainReducer, applyMiddleware(thunk))}>
    <Router history={history}>
      <Main />
    </Router>
  </Provider>,
  document.getElementById('root')
);

ou si vous ne souhaitez pas utiliser un fichier d'historique personnalisé et importer à partir de là, vous pouvez le créer directement dans votre index.js:

import { createBrowserHistory } from "history";

const history = createBrowserHistory();

ReactDOM.render(
  <Provider store={createStore(mainReducer, applyMiddleware(thunk))}>
    <Router history={history}>
      <Main />
    </Router>
  </Provider>,
  document.getElementById('root')
);
0
devserkan