0
votes

First of all I want to say that I'm new to javascript and react world so sorry in advance if my question is trivial but I can't figure out this situation. I will update the post if needed.

I want to migrate my current application to single page application. I have 3 main pages PageA, PageB and PageC (in react I have 3 main components). I want to be able to switch between these 3 pages/components. Lets say that I have this LogoText which is the component that represents the logo of the site. I want to have it in all other components (including the PageA) and when I click on it I want to render the main page ( PageA ).

So I'm trying to build a it with react and webpack . In this simple example given below I have a main page component MainPage.js which is parent component for all components that should be in the main page and a LogoText component which should render the MainPage component when someone click on it. When all this components are in one file and I don't use require() everything is working perfectly but when I break down my app into modules using require() and package it with webpack I get strange behaviour. I can load the MainPage component and the LogoText component is displayed correctly in the MainPage but when I click on the LogoText I get "Uncaught Invariant Violation: Element type is invalid" exception (click for screenshot)

first exception:
react.js:18798 Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).

second exception:
react.js:18354 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

I have the following 3 classes:

main.js:

var MainPage = require("./MainPage.js")

ReactDOM.render(
   <MainPage />,
   document.getElementById('content')
);

MainPage.js:

var LogoText = require("./LogoText.js")

var MainPage = React.createClass({

    render: function() {
        return (
            <div>
                Hello page,
                <LogoText />
            </div>
        );
    }
});

module.exports = MainPage;

LogoText.js

var MainPage = require("./MainPage.js")

var LogoText = React.createClass({

    changePage: function(e) {
        ReactDOM.render(
            <MainPage />,
            document.getElementById('content')
        );
    },

    render: function() {
        return (
            <span onClick={this.changePage}>logo</span>
        );
    }
});

module.exports = LogoText;

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Tutorial</title>
    <!-- Not present in the tutorial. Just for basic styling. -->
    <link rel="stylesheet" href="css/base.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.16/browser.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script src="scripts/bundle.js"></script>
  </body>
</html>

UPDATE 1: Here is my webpack.config.js:

module.exports = {
    entry: "./src/scripts/main.js",
    output: {
        path: "./src/scripts",
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" },
            { test: /\.js$/, loader: 'jsx-loader?insertPragma=React.DOM&harmony'},
        ]
    },
    externals: {
        //don't bundle the 'react' npm package with our bundle.js
        //but get it from a global 'React' variable
        'react': 'React'
    },
    resolve: {
        extensions: ['', '.js', '.jsx']
    }
};
1
post the webpack.config.js, I dont see an obvious error in the react codeomarjmh
I have updated the post pasting my "webpack.config.js" file contentGeorgi Staykov
ReactDOM.render should not be in LogoText. You are not "thinking in React."Sam H.
Yup missed that one, thats no good..omarjmh
Ok then how should I render the MainPage from the LogoText ? I have tried rendering another pages with ReactDOM.render in the exact same way and it is working. There is a problem only in this case. I can guess that it is because of the circular require()Georgi Staykov

1 Answers

0
votes

Ok obviously my intuition was correct "I can guess that it is because of the circular require()". The answer is here : "circular imports with webpack returning empty object".

I think that react router will be the correct way to implement this. I will try it and I will post the results here later :)

UPDATE 1:
React router is exactly what I'm searching for. This is the exact tutorial that solved my problem.