简体   繁体   中英

react-router-dom v5 - Link works, but Redirect and history.push() do not

EDIT: I'm embarrassed to say that the answer was a typo in the URLs I was sending to Redirect and history.push(). So for anyone wondering, seems like Link, Redirect, and history.push() should work the same.


Why would Link work fully, while Redirect and history.push() only update the URL but do not render the component at that URL?

I want to do the following:

  • User clicks a button, which calls a server-side function through a Redux action creator
  • The server function writes data to the Firebase Firestore
  • The server function returns the document ID, which is used by the action creator to history.push() the specific URL that displays the new document in the front end.

This results in the correct URL in the browser, but does not render the component that it should. I tested hard-coding a Redirect and a Link to the same URL, and only the Link works fully.

What I've tried:

  • Using BrowserRouter, Router, and HashRouter
  • Putting the Router of choice both outside and immediately inside the App component
  • Using useHistory() to access history and passing history to the action creator from my component
  • Using a history config file, passing it as a component to Router, and importing it to the action creator file

index.js file:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import { Router } from 'react-router-dom'

import history from './config/history'

// firebase and store config ommitted

ReactDOM.render(
  <Provider store={store}>
    <ReactReduxFirebaseProvider {...rrfProps}>
      <Router history={history} >
        <App />
      </Router>
    </ReactReduxFirebaseProvider>
  </Provider>,
  document.getElementById('root')
);

history.js

import { createBrowserHistory } from 'history'
const history = createBrowserHistory()
export default history;

action creator

import history from '../../config/history'

export const importWebsite = (data) => {
  return (dispatch, getState, { getFirebase }) => {
    const firebase = getFirebase()
    const profile = getState().firebase.profile
    const userId = getState().firebase.auth.uid

    data = {
      ...data,
      userFirstName: profile.firstName,
      userLastName: profile.lastName,
      username: profile.username,
      userId: userId,
    }
    const pull_website = firebase.functions().httpsCallable('pull_website')
    pull_website(data)
      .then((res) => {
        dispatch({ type: 'IMPORT_SUCCESS' })
        history.push('/websites/' + res.data.id)
      }).catch((err) => {
        dispatch({ type: 'IMPORT_FAIL', err })
      })
  }
}

Barring any weirdness like rendering parts of your app into multiple Router components, then I believe the issue here is that your routing context is inside the redux provider, or in other words, there is no Router or routing context higher above the redux provider (and asynchronous action middleware) in the ReactTree.

Solution: Wrap the Router around the Provider .

ReactDOM.render(
  <Router history={history} >
    <Provider store={store}>
      <ReactReduxFirebaseProvider {...rrfProps}>
        <App />
      </ReactReduxFirebaseProvider>
    </Provider>
  </Router>,
  document.getElementById('root')
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM