web-dev-qa-db-ja.com

React history.Push()が新しいコンポーネントをレンダリングしない

みなさん、こんにちは!

シンプルなサインイン機能を持つReact.jsプロジェクトがあります。ユーザーが承認されたら、history.Pushメソッドを呼び出します。このメソッドは、アドレスバーのリンクを変更しますが、新しいコンポーネントをレンダリングしません。 (私はBrowserRouterを使用しています)

私のindex.jsコンポーネント:

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

私のMain.jsコンポーネント:

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

export default withRouter(Main);

私のアクション作成者

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

私のSignin.jsコンポーネント:

 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
}

奇妙なことに、handleSubmit()メソッドをこれに変更すると、すべてが完璧に機能します。

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

同じ問題は、componentWillReceiveProps(newProps)メソッドから履歴をプッシュしようとした場合にも発生します。アドレスが変更されますが、新しいコンポーネントはレンダリングされません。誰かがこれがなぜ起こるのか、そしてそれを修正する方法を説明できますか?

ありがとうございました!

6
zilijonas

誰かが興味を持っている場合-これは、履歴がプッシュされる前にアプリがレンダリングされていたために起こりました。履歴のプッシュをアクションに入れたが、結果がJSONに変換される直前に、それが機能し始めたので、履歴がプッシュされてから、アプリがレンダリングされます。

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

これでは機能しません->

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
}

このhandleSubmitメソッドでは、Promiseの中でthis.props.history.Push()を呼び出しているため、thisは現在のクラスインスタンスではなくPromiseのインスタンスを指します。

これをお試しください->

 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
}

今この声明の中で->

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

This.props.history.Push()は正しくないため、Current Classインスタンスを参照しています。

0
Harish Soni

BrowserRouterの代わりにカスタム履歴とルーターを使用してみてください。履歴をインストールした後:

yarn add history

カスタムのブラウザ履歴を作成します。

import { createBrowserHistory } from "history";

export default createBrowserHistory();

セットアップでBrowserRouterの代わりにルーターを使用します。

import history from "your_history_file";

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

または、カスタム履歴ファイルを使用せずにそこからインポートする場合は、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