React history.push() 不渲染新组件

IT技术 javascript reactjs react-router-v4
2021-04-17 03:02:12

我有一个带有简单登录功能的 React.js 项目。用户获得授权后,我调用 history.push 方法更改地址栏中的链接但不呈现新组件。(我使用浏览器路由器)

我的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个回答

如果有人感兴趣 - 发生这种情况是因为应用程序在推送历史记录之前正在呈现。当我将历史推送放入我的操作中但就在结果转换为 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);
      }
    });
  });

您需要申请 withRouter 才能在每个使用“push”的组件中使用 this.props.history.push('/page')

import { withRouter } from 'react-router-dom';
.....
export default
        withRouter(MoneyExchange);

这在使用推送时很重要。

如果您确实像我一样有另一个更高阶的组件(aws withAuthenticator),您可以将一个组件包裹在另一个组件上,它也可以正常工作。像这样: export default withRouter(withAuthenticator(ListNotesPage));
2021-06-07 03:02:12

首先,使用 history 包创建一个历史对象:

// src/history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();

然后将其包装在主路由器组件中。

    import { Router, Route, Link } from 'react-router-dom';
    import history from './history';

    ReactDOM.render(
        <Provider store={store}>
          <Router history={history}>
            <Fragment>
              <Header />
              <Switch>
                <SecureRoute exact path="/" component={HomePage} />
                <Route exact path={LOGIN_PAGE} component={LoginPage} />
                <Route exact path={ERROR_PAGE} component={ErrorPage} />
              </Switch>
              <Footer />
            </Fragment>
      </Router>
    </Provider>)         

在这里,发送请求后,重定向到主页。

    function requestItemProcess(value) {
        return (dispatch) => {
            dispatch(request(value));
            history.push('/');
        };

    }   

应该有帮助:)

尝试使用自定义历史记录和路由器而不是 BrowserRouter。安装历史记录后:

yarn add history

创建自定义浏览器历史记录:

import { createBrowserHistory } from "history";

export default createBrowserHistory();

在您的设置中使用 Router 而不是 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')
);
奇怪,我用这种方式解决了类似的问题。React+Redux 和 history.push。但是,您的问题可能会有所不同,因为在 then 块之外它正在为您工作。我希望你能找到解决办法。最后一件事,如果可能的话,从您的主应用程序中删除 withRouter,然后根据我的建议重试。
2021-05-28 03:02:12
不幸的是,这段代码也有同样的问题。:(
2021-06-10 03:02:12
仍然不起作用。我相信这个问题更多地与我的请求的异步性有关。
2021-06-19 03:02:12

不工作在这个->

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方法中你是this.props.history.push()在一个thisPromise内部调用,所以 指向 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() 因为它超出了Promise并引用了 Current Class 实例。

呃,对不起,错过了那部分。添加。现在推送有效,但同样的问题仍然存在 - 地址更改,成功记录,服务器组件仍未呈现。如果这个问题与Promise有关 - 为什么 history.push 不能与 componentWillReceiveProps 一起使用,在那里我收到名为 loginIn 的道具,然后 push() 被激活,但完全相同的问题仍然存在 - 新组件未呈现。
2021-05-30 03:02:12
这是一个不好的榜样。this.props.history.push('/servers')从Promise的异步执行中删除无论是否onLoginRequest成功完成,该行都不会触发类似地,假设它正在进行网络调用,它可能会在上面的Promise解决之前执行。
2021-05-31 03:02:12
然后它说:“推未定义”。我也试过这样: this.props.onLoginRequest(username, password).then(result => { console.log("Success.Token: "+result.token); this.props.history.push(' /servers') }); - 也没有用。
2021-06-13 03:02:12
您是否添加了这一行 - > const { history: { push } } = this.props;
2021-06-15 03:02:12