5

This seems like a duplicate of a few others. But no solution has worked for me.

Navigating via links works fine. Refreshing pages or manual navigating only works on desktop (chrome and firefox, not working on Safari). On desktop safari, and all iOS browsers, it simply shows the entire JSON object in the browser and doesn't seem to be serving the static files.

I’ve tried Router, BrowserRouter and HashRouter. The only one that works is HashRouter. But, I don’t want hashes in the url.

I'm not getting any errors, and I've console logged all over. When I placed a log in the getProducts action creator and on the server "/products" route, Safari doesn't show the action creator console log in the browser. But, heroku logs show that the path="/products" is being hit, but not the path="/static/css/main.etc.," or path="/static/js/main.etc.," files.

Things I've looked into and/or tried:

React-router urls don't work when refreshing or writting manually

Web page not rendering correctly in iOS browsers or desktop Safari

https://github.com/ReactTraining/react-router/issues/4727

How to remove the hash from the url in react-router

React Routing works in local machine but not Heroku

https://github.com/ReactTraining/react-router/issues/4671

Here's a stripped back sample. Note: I'm using concurrently to proxy my requests.

// client/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import './styles/index.css';
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import { Router } from 'react-router-dom'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import reduxThunk from 'redux-thunk'
import history from './history'

import reducers from './reducers'

const store = createStore(
  reducers,
  applyMiddleware(reduxThunk)
)

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

// client/history.js

import createHistory from 'history/createBrowserHistory'
export default createHistory()

// client/App.js

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom'
import Home from './components/home'
import Header from './components/header'
import Products from './components/products'
import './styles/App.css'

class App extends Component {
  render() {
    return (
      <div>
        <Header />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/products" component={Products} />
          <Route render={() => <p>Not found</p>} />
        </Switch>
      </div>
    );
  }
}

export default App;

// client/components/products.js

import React, { Component } from 'react'
import { connect } from 'react-redux'
import * as actions from '../actions'
// import ‘../polyfill’ // imported polyfil object from core-js when previously using Object.values below… same results either way…

class Products extends Component {

    componentWillMount() {
        this.props.getProducts()
    }

    renderProducts() {
/*      const { products } = this.props
        return Object.values(products).map((product) => {
        return (
            <li key={product.title}>
                {product.title}
            </li>
        )
        });*/
        const productsArray = []
        const { products } = this.props
        for(let key in products) {
            productsArray.push(<li key={products[key].title} >{products[key].title}</li>)
        }
        return productsArray
    }

    render() {
        if(!this.props.products) {
            return (
                <div></div>
            )
        }

        return (
            <div>
                <ul className="productListItemUl" >{this.renderProducts()}</ul>
            </div>
      )
    }
}

const mapStateToProps = state => {
    return { products: state.products.products }
}

export default connect(mapStateToProps, actions)(Products)

// actions/index.js

import axios from 'axios'
import {
    GET_PRODUCTS
} from './types'

export function getProducts() {
    return async function(dispatch) {
        try {
            const products = await axios.get('/products')
            dispatch({ type: GET_PRODUCTS, payload: products.data })
        } catch (err) {
            console.log('redux thunk getProducts() action creator error')
            console.log(err)
        }
    }
}

// server.js

"use strict";

require("babel-core")

const express = require('express');
const path = require('path');

const app = express();
const port = process.env.PORT || 3050;

const mongoUtil = require('./server/mongoUtil')
mongoUtil.connect()

const bodyParser = require('body-parser');
const jsonParser = bodyParser.json();
app.use(jsonParser);

if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.resolve(__dirname, 'client/build')));
}

let productsRoute = require('./server/routes/products');
app.use('/products', productsRoute)

app.get('*', function(request, response) {
  response.sendFile(path.resolve(__dirname, 'client/build', 'index.html'));
});

app.listen(port, () => console.log(`Listening on port ${port}.`));
T-G
  • 181
  • 2
  • 7
  • 3
    For anyone in a similar boat: I ended up splitting my server and client apps and deploying them to heroku separately, and now it works just fine. So I guess I probably just failed to set something up properly on heroku to get the proxy working correctly, or maybe it just doesn’t play nice altogether. I’m not sure and I didn't look further into it, but it’s working now that I’ve deployed the client and server separately. – T-G Jul 14 '17 at 19:58

0 Answers0