Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting mobile in an isomorphic reactjs

How should I implement detecting mobile in my reactjs + express? I used mobile-detect to determine if mobile but first I implemented it with const md = new MobileDetect(window.navigator.userAgent) but I remembered window doesn't exist when it's server loaded. The example in express section should work because that's the only place I could access req but how do I pass it in my react app to be used afterwards?

UPDATE

// app.js

...
import { routes } from './routes';
import { match, RouterContext } from 'react-router';
import { renderToString } from 'react-dom/server';

...
const app = express();
app.use(express.static('public'));

app.set('view engine', 'ejs');

app.get('*', (req, res) => {
  // routes is our object of React routes defined above
  match({ routes, location: req.url }, (err, redirectLocation, props) => {
  if (err) { // something went badly wrong, so 500 with a message
    res.status(500).send(err.message);

  } else if (redirectLocation) { // we matched a ReactRouter redirect, so redirect from the server
    res.redirect(302, redirectLocation.pathname + redirectLocation.search);

  } else if (props) { // if we got props, that means we found a valid component to render for the given route
    const reducer = combineReducers(reducers);
    const store = applyMiddleware(...middlewares)(createStore)(reducer);

  ...
const server = http.createServer(app);
const port = process.env.PORT || 3003;

server.listen(port);
server.on('listening', () => {
  console.log('Listening on ' + port);
});

// client-render.js
import { routes } from './routes';
import { Router, browserHistory } from 'react-router'

ReactDOM.render(
  <Provider store={store}>
    <Router onUpdate={() => {scrollTop(); handleNotifs(store)}} routes={routes} history={browserHistory} />
  </Provider>,
  document.getElementById('app')
);

// routes.js
import AppComponent from './components/app';
import IndexComponent from './components/index';
...

const routes = {
  path: '',
  component: AppComponent,
  childRoutes: [{
    path: '/',
    component: IndexComponent,
    name: 'home'
  }, {...}]
}
like image 776
index Avatar asked May 05 '16 12:05

index


1 Answers

I accomplished exactly what you are requiring by making my routes module become a function that takes the user-agent. It then simply returns an array or nested routes. Here's an example...

routes.js

module.exports = (userAgent) => {
  const md = new MobileDetect(userAgent)
  if (md) { // not sure on the syntax of MobileDetect?
    return {
      // return mobile routes
    }
  } else {
    return {
      // return desktop routes
    }
  }
} 

app.js

app.get('*', (req, res) => {
  match({ routes: routes(req.headers['user-agent']), location: req.url }, (err, redirectLocation, props) => {
    // continue as normal
  }
}

client-render.js

ReactDOM.render(
  <Provider store={store}>
    <Router onUpdate={() => {scrollTop(); handleNotifs(store)}} history={browserHistory}>
      {routes(navigator.userAgent)}
    </Router>
  </Provider>,
  document.getElementById('app')
);

On a side note, using this approach we are able to also pass in the auth cookie to the routes so the onEnter methods can redirect if the route is behind login.

Hope this helps! BTW React-Router is the best!! I got to meet the creators in NYC and they're top notch.

like image 104
BradByte Avatar answered Oct 20 '22 21:10

BradByte