Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a cleaner way of getting current URL in both client and server side in isomorphic react apps?

I am developing an app based in this React Redux boilerplate. In one component I need to get the current URL when component is mounted in order to generate a shareable URL for social media. Than component is being accesible from dynamically generated URLs with React Router. In client side I wouldn't have any problem by getting it through javascript document object but the problem lies server side.

I thought about making available in the Redux store the Node.js environment data kept in this config.js file, where hostname is kept

// Node.js environment file config.js    
require('babel-polyfill');

const environment = { 
  development: {
    isProduction: false
  },  
  production: {
    isProduction: true
  }
}[process.env.NODE_ENV || 'development'];

module.exports = Object.assign({
  host: process.env.HOST || 'localhost',
  port: process.env.PORT,
  apiHost: process.env.APIHOST || 'localhost',
  apiPort: process.env.APIPORT
}, environment);

and with the location object of React Router set as props in the component get the pathname and fully construct the URL.

What I have done is to create a simple reducer with an initial state to keep the Node.js config enviroment data and just the default action to include in my combineReducers function with the other app reducers.

const initialState = { 
  config: {}
};

export default function config(state = initialState, action = {}) {
  switch (action.type) {
    default:
      return state;
  }
}

And then I injected the Node.js object with the environment data in the creation of the store, as initial state data, in my server.js file.

import config from './config';
...
const store = createStore(memoryHistory, client, {config});
...

Thus I have available the hostname and I am able in the component to construct its full url both client and server side through Redux store.

But, is there any simpler / cleanest way? I am afraid I might be overkilling it or creating any security issue to my app.

like image 370
Dez Avatar asked Mar 09 '17 13:03

Dez


People also ask

What is isomorphic rendering?

Isomorphic in the context of web development means rendering pages on both the server and client side. This also implies the use of JavaScript and Node. js for the sole purpose of the code re-use of libraries, allowing browser JavaScript code to be run in the Node. js environment with very little modification.

What is isomorphic rendering in react?

Definition of Isomorphic React App: Isomorphic React App is a web app that consists of code that can run on both server and client-side. It usually takes full advantage of performance and SEO friendliness from the server. And combine it with browser capabilities to handle complex user interactions.

What is server side rendering react?

What is Server-Side Rendering? Server-side rendering with JavaScript libraries like React is where the server returns a ready to render HTML page and the JS scripts required to make the page interactive. The HTML is rendered immediately with all the static elements.


1 Answers

I was having this issue when attempting to use Helmet server-side. I passed in the request as a prop to my main <App> component and then use either that request object (server-side) or the window object (client-side).

App.js

render() {

    // Get full url from client or server
    let fullURL = ''
    if(typeof window !== 'undefined'){
        fullURL = window.location.protocol + '//' + window.location.host + this.props.location.pathname
    }else if(this.props.serverRequest){
        fullURL = this.props.serverRequest.headers.host + '/' + this.props.location.pathname
    }

    const urlTag = fullURL === '' ? null : <meta property="og:url" content={fullURL} />
    const linkTag = fullURL === '' ? null : <link rel="canonical" href={fullURL} />

    const helmet = this.props.siteInfo.site
        ? <Helmet>
            <title>{this.props.siteInfo.site.title}</title>
            <meta property="twitter:title" content={this.props.siteInfo.site.title} />
            {urlTag}
            {linkTag}
            <meta property="og:type" content="website" />
          </Helmet>
        : null

    return (
        <div>
            {helmet}
            <Notices />
            <div className="body">
                <Header />
                <Body />
            </div>
            <Footer />
        </div>
    )
}

server.js

const markup = renderToString(
    <Provider store={store}>
        <StaticRouter location={req.url} context={context}>
            <App serverRequest={req} />
        </StaticRouter>
    </Provider>
)

const helmet = Helmet.renderStatic()

Is this "proper" or "best practice"? No idea, but it works well and is easy to follow :)

like image 50
Gurnzbot Avatar answered Nov 15 '22 13:11

Gurnzbot