Search code examples
javascriptreactjswebpackreact-routerreact-router-redux

React not rendering component with URL param


I'm creating a website that will have the following:

  1. A page that has a list of items.
  2. A page that will show more details about an individual item

I'm using react-router ^3.0.0, react-router-redux ^4.0.7, and webpack 2.1.0-beta.20 in the site. I'm trying to set up my routes like so:

import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import thunk from 'redux-thunk';
import {Router, Route, browserHistory} from 'react-router';
import {combineReducers, createStore, applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import {routerReducer, syncHistoryWithStore} from 'react-router-redux';
import {IntlProvider, intlReducer} from 'react-intl-redux';
import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';

import {Home} from './app/components/Home/Home';
import Profile from './app/components/Profile/Profile';
import Login from './app/components/Login/Login';
import SignUp from './app/components/SignUp/SignUp';
import Items from './app/components/Items/Items';
import Item from './app/components/Item/Item';
import {requireAuthentication} from './app/components/General/AuthenticatedComponent';
import {reducers} from './app/reducers/reducers';
import {i18n} from './app/i18n/i18n';

import './index.scss';

addLocaleData([
    ...en
]);

// Create the store from the reducers
const store = createStore(combineReducers({
    reducers,
    routing: routerReducer,
    intl: intlReducer
}), i18n, applyMiddleware(thunk));

// Create an enhanced history that syncs navigation events with the store
const history = syncHistoryWithStore(browserHistory, store);

ReactDOM.render(
    <Provider store={store}>
        <IntlProvider locale="en" defaultLocale="en">
            <Router history={history}>
                <Route path="/" component={Home}/>
                <Route path="/profile" component={requireAuthentication(Profile, true)}/>
                <Route path="/login" component={requireAuthentication(Login, false)}/>
                <Route path="/signup" component={requireAuthentication(SignUp, false)}/>

                {/* Items route lists all of the items, Item shows details for one individual item */}
                <Route path="/items" component={Items}/>
                <Route path="/items/:itemId" component={Item}/>
            </Router>
        </IntlProvider>
    </Provider>,
    document.getElementById('root')
);

The Items and Item components are unrelated, and do not depend on each other.

When I navigate to http://localhost/items, the Items component renders. But when I navigate to http://localhost/items/1, nothing renders, and I get the following error in the console:

GET http://localhost:3000/items/index.js

I've tried to fix this a few ways, each resulting in the same error message

...
<Route path="/items" component={Items}/>
<Route path="/items/:itemId" component={Item}/>
...

...
<Route path="/items" component={Items}>
    <Route path="/:itemId" component={Item}/>
</Route>
...

...
<Route path="/items">
    <IndexRoute component={Items}/>
    <Route path="/:itemId" component={Item}/>
</Route>
...

I am able to get the Item component to render with the param when I do this though

...
// Navigate to http://localhost:3000/1
<Route path="/:itemId" component={Item}/>
...

But that's not how I want the URLs to be set up. Does anyone know how to fix this problem? Thanks for the help!


Solution

  • So it turns out that this was not a react-router problem, but instead a webpack problem. I took a look at the source code that was being compiled, and it looked like this

    <!doctype html>
    <html>
        <head>
            <meta charset="utf-8">
            <meta name="description" content="">
            <meta name="viewport" content="width=device-width">
    
            <link href="https://fonts.googleapis.com/css?family=Lato:300,400,7s00" rel="stylesheet">
            <link rel="icon" type="image/png" href="http://fountainjs.io/assets/imgs/fountain.png" />
            <title>My Web App</title>
    
            <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css></link>
        </head>
        <body>
            <!-- Entry point for the application -->
            <div id="root"></div>
    
            <script type="text/javascript" src="index.js"></script>
        </body>
    </html>
    

    The index.js file should be linked as /index.js, otherwise it looks in the current directory that the route is in. So in my webpack.conf.js file, I found a section that mentions index.js

    output: {
        path: path.join(process.cwd(), conf.paths.tmp),
        filename: 'index.js'
    }
    

    I simply changed it to

    output: {
        path: path.join(process.cwd(), conf.paths.tmp),
        filename: '/index.js'
    }
    

    And it worked. The index.js file is now linked properly in the source