How to use React in multiple places in a normal website - javascript

I have a new website which isn't a single page app but a server rendered website (asp.net using Umbraco CMS). I used to use Angular 1.x in my websites, which is easy because you just load it in with script tags and the code is uncompiled.
I have been using React recently in SPAs started with create-react-app which looks after webpack, babel etc. for you and produces a single bundle. However, I want to use React in several places on the website like the main header/menu, contact forms etc so it makes sense to produce multiple bundles, although these bundles may share imports (Moment.js, Formik etc.).
There are instructions on the React website showing how to include a single script and attach it to an element in yourwebsite, but no complex examples.
So, how do I go about setting up something that will transpile everything without duplicating code in bundles. Do I need some kind of master bundle loaded on all pages and individual bundles for things like a contact form?
Secondly, how do I wire everything up? In an SPA you just have a root node and bind your app to the root node using react-dom, but if you've got mini pieces of react functionality littered through your app then do you need some kind of master script to bind everything to the right elements?
Any help would be greatly appreciated, even if it's just pointing me in the direction of some kind of boilerplate project.
Oh, and I'm not interested in doing a server side rendered Next JS app or anything like that, I think that could get too complicated to integrate with the CMS.

I think you can make a single bundle, rendering multiple component to different places. I created a little example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
return (
<div className="App">
<h1>Body</h1>
</div>
);
}
function Footer() {
return (
<div className="App">
<h1>Footer</h1>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
const footerElement = document.getElementById("footer");
ReactDOM.render(<Footer />, footerElement);
You can play with it in this sandbox example. https://codesandbox.io/s/34nvv4nvy5

In addition to the answer above you can exclude React, ReactDOM or/and React Router (and any other dependencies) from your bundles and include them on the page so you aren't bundling them X amount of times. This way you can have separate entry files for each application.
webpack.config.js
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
}
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js" integrity="sha256-JBRLQT7aJ4mVO0H2HRhGghv/K76c5WzE57wW0Flc6ZY=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/cjs/react-dom.production.min.js" integrity="sha256-j2ERTIovDFVe0R+s0etuSiBQ2uxrNE6q0ow/rXxHvLA=" crossorigin="anonymous"></script>

If you want to render elements "outside" your root element of the react application, then you can use react Portals. We are using this approach as well and it's going well.
If you still think you want multiple mini react applications that run on the same page, you can communicate with them with the help of ReactDOM.render. Basically, ReactDOM.render can get invoked multiple times, it won't re-mount the entire application but instead will trigger updates and diffing to the react tree (same as a normal render method of components).
In fact, i wrote an article with a tutorial on how to Integrate React with other applications and frameworks.
I also tried to simulate this approach with a codesandbox example
Hope that helps.

Related

Astro - react useEffect hook is not working

I am trying to build a web app with Astro + Reactjs, but I got an issue on calling useEffect. Basically useEffect is not calling, I don't get any logs in the terminal or any warnings/errors in the terminal or in the browser.
I am exporting the function as: export default function SecondSection(){}, I changed the file extension from .jsx to .tsx, still no result. I followed all instructions from astro docs to integrate react.
I am trying to use react hooks, like useEffect/useState, but for some reasons it's not working any of that.
What can cause that issue? Thank you for your time.
The first thing to check would be to make sure you are hydrating your React component where you’re using it. In Astro, components ship zero JS by default, just plain HTML. Components will only be interactive in the browser if you add a client:* directive. This is part of Astro’s “Islands Architecture”.
To include a component’s JS you need a client directive saying when to load it. In this example the component will load its JS when the page loads:
---
// src/pages/index.astro
import SecondSection from '../components/SecondSection.jsx';
---
<SecondSection client:load />
There are different directives like client:idle or client:visible that you can use to control exactly when a user needs the interactivity. There’s more about the client directives in Astro’s docs.

Integrating template with current project

I currently have a React web app that I am creating, (used create-react-web-app). I want to integrate the following template: https://www.creative-tim.com/product/material-dashboard-react
on the user account page however since this is an entire web app, am having difficulties doing so (there are differences in package.json, and file structures ect).
Currently, I have the basic setup with firebase and am doing the following:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
render(<UserPage user={user}>, document.getElementById("root"));
} else {
render(<App user={user}>, document.getElementById("root"));
}
}
I want to set it up so that this template is shown on the UserPage.
I have tried to copy files over, and change the package.json to cooperate with both my current app, and the template.
I dont know exactly what you want to accomplish?
If its working wheres the problem?
In the end the react code cann be confusing in terms of where to start the app. But in the end when you use webpack to build your app, the JSX will be replaced by native JS and therefore you just have to call ReactDOM.render in the JS file you want to append the element.

How to add/use React component in only one part (cart page) of my existing node project?

Up until now I have been using create-react-app to build React applications and components.
However, I have a project that I'm working on which was built in node using pure JS for Dom manipulation and I wanted to add react to one page only (the cart page).
All tutorials I had watched assume you are starting project from scratch and I can't seem to figure out how to add React to just a single part of my project.
Can someone point me in the right direction?
I would recommend you start here:
https://reactjs.org/docs/rendering-elements.html
The React Docs actually also point at this tutorial for a non 'create-react-app' tutorial: https://blog.usejournal.com/creating-a-react-app-from-scratch-f3c693b84658
This is the React Docs for rendering elements. The TLDR version:
In your HTML file, where you want your React component to go, create an empty div and give it a unique name (i.e. 'app' or 'react-component')
Then create your component, etc. and have ReactDOM render on the unique id name.
To get it to render, in your node app, point it at the build path, typically bundle.js
I have got this working and managed to use React components (written in JSX) for specific parts of my custom JavaScript app (bundled via Webpack). You basically need three things.
1) Your custom JavaScript app
// MyApp.js
import { renderMyReactComponent } from "./MyReactComponent.jsx";
class MyApp {
// Call this when you want to show your React component
showMyReactComponent() {
// Create an empty div and append it to the DOM
const domElem = document.createElement("div");
domElem.classList.add("my-react-component");
document.append(domElem);
// Render your React component into the div
renderMyReactComponent(domElem);
}
}
2.) Your React component
// MyReactComponent.jsx
import React from "react";
import ReactDOM from "react-dom";
class MyReactComponent extends React.Component {
render() {
// JSX, woah!
return <h2>My React Component</h2>
}
}
// A way to render your React component into a specific DOM element
export const renderMyReactComponent = (domElem) => {
// NB: This syntax works for React 16.
// React 18 requires a slightly different syntax.
ReactDOM.render(
<MyReactComponent />,
domElem
);
}
3.) A way to parse jsx files and build the app
I use Webpack and amended my existing Webpack configuration based on this article: https://medium.com/#JedaiSaboteur/creating-a-react-app-from-scratch-f3c693b84658 (The official React documentation also points at this tutorial)
Useful Articles
A good read is this article from the official React documentation: https://reactjs.org/docs/add-react-to-a-website.html. This also explains a different way to integrate a React component into your existing JavaScript app using script tags instead of Webpack.
You might also be interested in this answer to a similar question as yours.
As #pinkwaffles pointed out in their answer, the following article helps to understand rendering a React component into a DOM element: https://reactjs.org/docs/rendering-elements.html
PS: Note that at the time of writing this answer, the above articles already use React 18 for their examples, whereas my above example still uses React 16; so the syntax regarding ReactDOM is a little different. But the idea is the same.

react vs react DOM confusion

I'm using ES6 babel with react, and now for the newer version react, react DOM is not a part of it anymore. My doubt for below code is that, is it the first line require? since nowhere I need React, but the last line I need ReactDOM.
const React = require('react')
const ReactDOM = require('react-dom')
const App = () => {
return (
<div className='app-container'>
<div className='home-info'>
<h1 className='title'>sVideo</h1>
<input className='search' type='text' placeholder='Search' />
<button className='browse-all'> or Browse All</button>
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('app'))
React from version 0.14 onwards is split into two parts: React and ReactDOM. You are making use of ReactDOM to render you HTML element. So it definitely makes sense for you to import ReactDOM in your Component. But as far as React is concerned although you are not making use of React directly but it is indirectly being used because whatever you write in your return statement will be transpiled into React.createElement function that will create the actual DOM elements.
Now you can see this if you omit React in your code, you will see an error that
react is not present
and it will give you that React is not recognised in React.createElement. Hope you understood it.
From the docs of ReactDOM:
This package serves as the entry point of the DOM-related rendering paths. It is intended to be paired with the isomorphic React, which will be shipped as react to npm.
So your ReactDOM is specifically for DOM related paths for rendering. This used to come tightly coupled with the React package itself, but the built in DOM in React has become deprecated.
Now, Facebook ships the ReactDOM separately as its own package, so yes, you need to include it in your app if you're planning on rendering any of your React. And you also definitely need React itself — ReactDOM is just the DOM side.
Here's a reddit post that explains the separation from React and ReactDOM.
The React team are working on extracting all DOM-related stuff into a separate library called ReactDOM. 0.14 is the first release in which the libraries are split.
Little fun fact, since they want to support backwards compatibility, they kept React's internal DOM but deter people from using it in a funny way.
They are separated from version 0.14 and for any react project, you need to include both, ReactDOM is laying on React, and React, without ReactDOM could not be rendered to the DOM, so the Answer is a big Yes!
React has the need to separate core react code that has nothing to do with generating a web application (HTML DOM). Particularly react-native, there are a different set of packages that are required for React Native and react-dom is not one of them.
If the react library had never split up that DOM related code, a react-native project would have core react code that would be dead weight and then need to be removed using tree shaking and dead code elimination to remove modules in which you have never imported as part of your app.
Having react split this code up makes a lot of sense.

What in React should actually be rendered

I am currently working on learning React and Redux. Now I am getting a better grasp on what the two do:
React - Render components on the page
Redux - Keep the state of the page
My question though is: what should I actually be rendering with React? Is React suppose to render the entire page, even the header that won't change? For instance, am I suppose to create a new component for the header (logo and tabs, not changing), or just add that to the HTML file I will be rendering to?
I would suggest adding absolutely everything as a React component. Have a single <div> in your html file that you mount your React app to. I found that when I started using React I would try and avoid writing extra code (sure, writing a component for a header rather than the raw HTML is extra lines).
But this introduces complexity, in a way. Different parts of your app are rendered differently. In the long run, in my experience, consistency and readability is more important than fewer lines of code.
BTW if you're using stateless functional components (which your header would be), it's barely any extra code.
import React from 'react';
export default Header = () => <header>My wonderful app</header>;
like most other frameworks, you will have your base 'index.html' file that will include all of your dependencies and then a body which contains a div that you will render your react components into. it will look something like this:
<html>
<head>
<-- script, css, framework files added here -->
</head>
<body>
<div id="reactApp"</div>
</body>
</html>
then your main app file in react will have something along the lines of this at the bottom:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('reactApp')
);
everything else can be rendered within React and passed along to that div view.
It's entirely possible to have a hybrid page. For example: keep the navbar as native HTML where as the content is React.
Remember, React is component oriented so you could think of it as small widgets.
However, you will often have different widgets share the same state. In this case, it's good to make them part of the same tree of components.
Your question doesn't have a definite answer. It depends on what your application state needs are, but use React for the dynamic pieces of your page. Those parts that you're thinking are going to change without a reload will probably keep a state, so that's where React's stage management could come in handy.

Categories