Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to take variable from outside reactjs

I need to take value of variable which placed outside of my react container.

<body>
    <div id='react-app'></div>

<script>
    var _variable = 3
</script>

</body>

I need to take this value in my react-component and if possible store this value in Store ( redux )

like image 582
Андрей Гузюк Avatar asked Feb 27 '17 18:02

Андрей Гузюк


People also ask

Can we export a variable in React?

If you are exporting a variable (or an arrow function) as a default export, you have to declare it on 1 line and export it on the next. You can't declare and default export a variable on the same line.

Can a function use variable from outside?

you have to declare the variable outside the function to use it. variables declared inside a function can only be accessed inside that function.


3 Answers

If you put the declaration script before the react-loading script, the react script should be able to access it.

<script type="text/javascript">
  var x = {{ user_details }};
</script>
<script src="/static/app.js"></script>
like image 141
Jesvin Jose Avatar answered Oct 10 '22 18:10

Jesvin Jose


Redux has an api to hydrate reducers when configuring store. The signature of createStore method is:

createStore(reducer, [preloadedState], [enhancer])

Meaning that you can define your configureStore method as:

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';

import reducerA from 'reducers/a'
import reducerUserDetails from 'reducers/user-details'

export default function configureStore(initialState = {}) {
  const reducer = combineReducers({
    reducerA,
    reducerUserDetails,
  });

  // If you want to use dev tools
  const composeEnhancers =
    process.env.NODE_ENV !== 'production' &&
    typeof window === 'object' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;

  const enhancer = composeEnhancers(
    applyMiddleware(
      thunk // If you want to have async actions
    )
  );

  return createStore(reducer, initialState, enhancer);
}

Then in your entry file such as index.js or similar, you would include the configureStore and call it while passing user details:

const store = configureStore({
  reducerA: {...},
  reducerUserDetails: window.userDetails || {},
});

ReactDOM.render(
  <Provider store={store}>
    <YourApp />
  </Provider>,
  document.getElementById('react-app'),
);
like image 20
gor181 Avatar answered Oct 10 '22 19:10

gor181


This is an interesting challenge with a whole bunch of technical approaches.

Singleton

The simplest approach that will work for most devs is taking advantage of the fact that ES6 modules are singletons. This means that you can configure an object in one module, and import it in another and know that the value will be the same.

That being said, we can easily pass in variables when we initiate the app.

Why not use global variables? You can definitely bring in global variables and call it a day, but then that would be an anti pattern that ES6 is trying to establish. Here's a great walk through on why to avoid global variables in JS

So, how can we do this then?

Lets control when we initiate a React App

First, wrap your reactDom.render() in a function:

import React from 'react'
import ReactDOM from "react-dom"
import { Provider } from "react-redux"
import MyApp from "./pathto/myapp.js"
import store from "./pathto/store.js"

window.RenderApp = function () {
    new ReactDom.render(
        <Provider store={store}><MyApp /></provider,   
        document.getElementById('root_element')
    );
}

So this should look fairly familiar to those of you who have been working with react and ES6. All we've done here is wrap it in a function that is bound to the window object so that it is available to outside JS.

Now, initializing your react app should now look something like this:

<div id="root_element"></div>
<script src="path/to/bundle.js></script>
<script>
    window.RenderApp();
</script>

So, how do we pass variables into it? Some of you may have guessed it already :) We've set up our app to accept variables through its parameters:

...
window.RenderApp = function (outside_variable) {
    new ReactDom.render(
        <Provider store={store}><MyApp someProp={outside_variable} /></provider,   
        document.getElementById('root_element')
    );
}

And in our HTML

...
<script>
    var x = 72;
    window.RenderApp(x);
</script>

What About Redux?

So this works fine if we want to add it to the props, of course, when we're using larger apps we use stores with redux. It's just more sane that way. So this is where that bit about taking advantage of singleton objects in ES6 comes into play.

Create A Default Store Module

Lets create a new file that will store the default value for a store. We'll call it defaultStore.js.

let defaultStore = {
        item: "one",
        other: "two"
    }

export default (defaultStore);

Now, lets introduce it to our reducer:

import defaultStore from "path/to/defaultStore.js"

export default function app( state = defaultStore, action ) {

    switch (action.type) {
        //...
    }

    return state;
}

Back to our function we build earlier, we include our default store:

...    
import defaultStore from "path/to/defaultStore.js"

window.RenderApp = function (outside_variable) {

    defaultStore.item = outside_variable;

    new ReactDom.render(
        <Provider store={store}><MyApp /></provider,   
        document.getElementById('root_element')
    );
}

Because this portion of the app will be called before the app renders, we are mutating the default store before the main store gets built.

And just one more time lets take a look at the js in the HTML

...
<script>
    var x = 72;
    window.RenderApp(x);
</script>

And that does the trick! You can even set entire outside stores this way, or create a fancy merging object witchcraft you want.

like image 28
Philll_t Avatar answered Oct 10 '22 19:10

Philll_t