I have some components like below:
Wrapper: wrap Loader and Page
Loader: some animation
Page: page content
code like this:
<body>
<div id="app"></div>
</body>
class Loader extends Component {}
class Page extends Component {}
class Wrapper extends Component {
render() {
return (
<Loader/>
<Page />
);
}
}
ReactDOM.render(<Wrapper />, document.getElementById('app'));
I want hide Loader and show Page component after DOM has compeletely loaded.
How should I write dom ready event in React?
like jQuery: $(window).on('ready')
TL;DR If I understand correctly, the answer is probably "not possible". But there is another solution...
Here's what I think you're trying to do, described as a series of steps:
page starts loading, <Loader /> component shows a "page loading" animation
page finishes loading, <Loader /> component is removed (or hidden) and <Page /> component is inserted (or shown) with the "real" page content.
Here's the problem: remember that you inject your React components into the page like this:
ReactDOM.render(<Wrapper />, document.getElementById('app'));
You can't actually inject a React component until the DOM is loaded. So by that time, either <Loader /> appears for about 2 milliseconds and disappears, or it doesn't appear at all (since the DOM is already loaded by the time it gets injected into the page).
If you're trying to show a throbber or other simple animation (like an animated GIF), I'd try a hybrid approach:
Set up your HTML like this:
<body>
<div id="app"><img src="throbber.gif" /></div>
</body>
In your script tag, include a JQuery "document ready" event handler to load the React component:
class Page extends Component {}
class Wrapper extends Component {
render() {
return (
<Page />
);
}
}
$(document).ready(function () {
ReactDOM.render(<Wrapper />, document.getElementById('app'));
});
Notice that I've left out the <Loader /> - the throbber image is doing the work of the loader.
The idea here is that while the page is loading, the throbber GIF will be throbbing away until the DOM is loaded, at which point JQuery's document ready event will fire & the contents of the div#app will be replaced.
I haven't tried this, but it should work, provided that React actually replaces the content of div#app, rather than just appending stuff to it. If that's not the case, then it's a simple matter of changing the document ready handler to something like this:
$(document).ready(function () {
$('div#app img').remove();
ReactDOM.render(<Wrapper />, document.getElementById('app'));
});
The approach I ended up using (No JQuery needed) is the following:
In the index.html, put the loader element right after the root div
<div id="root">
</div>
<div id="preloader" class="pre-loader">
<img src="..."> </img>
</div>
Then inside your index.js :
document.addEventListener("DOMContentLoaded", function(event) {
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<DashApp />
</BrowserRouter>
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
const loadingScreen = document.getElementById("preloader");
loadingScreen.style.opacity = 0;
loadingScreen.style.display = "none";
});
So basically we simply follow a similar approach to what the other answer suggests, but without the need of JQuery cause we listen to the loading event using
document.addEventListener("DOMContentLoaded", function(event) { }
Another approach would be just placing the loader inside the root div which means React will overwrite it by default when it loads:
<div id="root">
<div id="preloader" class="pre-loader">
<img src="..."> </img>
</div>
</div>
My personal full approach can be seen in this
Related
I am running into a simple issue that doesn't seem to have an answer on quick google search or Tailwind doc.
I am a Vuejs user but I have started learning React. I have opted to use TailwindCSS for testing my React application but I noticed there is some differences of Tailwind usage between Vuejs and React.
In Vue, I can control a child component via the parent component like so:
Parent component:
<template>
<div class="w-screen">
<ChildComponent class="w-1/2 mx-auto" />
</div>
</template>
With the child being able to centre on screen through the above parent component as should in the ChildComponent's class.
However, when I tried to do the same in React like so:
Parent component:
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
Nothin happens when I placed the CSS at the Homepage child component from the parent.
I am sure there is a simple answer but I wasn't about to search the doc or use any keywords to find this problem. Anyone got a hint or confirm this is intended in React or have I done something wrong with the installation?
This is less of a Tailwind question and more of a React question. You cannot use className on the Homepage component without passing it as a prop. In your case, Homepage is not expecting any className. So while making your Homepage component you have to provide a prop called 'className' then it will work fine.
Or if you simply use a div in place of Homepage it will work normally. Have a look at this codesandbox link
You need to consider that <Homepage/> is a React component and cannot accept HTMLAttrs just like that.
this example might clear it:
const app = () => {
<div className="bg-black">
<Homepage className="bg-red" />
</div>
}
const homePage = (props) => {
<div className={props.className}>
<h1 className="bg-red">hi</h1>
</div>
}
the className that you pass to <Homepage/> is actually a props rather than Html attribure.
In Vue it's fairly straightforward but in react you need to be explicit and use className in your component
// Creating component
const Button = ({ className, children }) => {
return <button className={`${className} bg-red-500`}>{children}</button>
}
export default Button
// Using component
<Button className="text-white">MyButton</Button>
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
views/Homepage
you have to receive props that are going to be passed as className
const homePage = ({className}) => {
<div className={className}>
<h1 className="bg-red">hi</h1>
</div>
}
export default homePage
then export your component
ReactDOM.render(
<App />,
document.getElementById('root')
So what should I understand when i see something like this at the end of the app? What does 'root' or 'demo' stand for?
It's the element that exists in the original HTML that all of the React contents go into. For example, if your HTML contains:
<body>
<div>Maybe some other content here</div>
<div id="root"></div>
</body>
React rendering into the #root means that everything App renders will be put into that element:
<div id="root">
<!-- App populates this element -->
</div>
The element selected to be populated can be any element you want - it doesn't have to be root or demo in particular.
I'm assuming you're using Create React App. Have a look at public/index.html. There you'll see <div id="root"></div> which is what document.getElementById('root') is referring to.
Inside the HTML main file index.html of a React App, normally, you might see a <div> tag with id=root.
This code:
ReactDOM.render(
<App />,
document.getElementById('root')
MEANS: Render the whole React App into the element with id=root.
Many React beginners are curious about this thing, so was I. Therefore I will try explaining this in simple words.
When Browser gets response from server and starts rendering, it goes to the root file which in most cases is public/index.html, and render the same file most first.
Inside this html a <div> element is written whose id is "root"
<div id="root"> <div>
Then control goes to another file that is index.js.
Inside this .js file, a component is used (in most React apps this component is called <App/>.
ReactDOM.render(
<App />
document.getElementById("root"),
);
This <App/> component is the most first component that is rendered on the screen. Every Component is defined inside this component or it's children.
And document.getElementById("root") renders the index.html file that is the root file.
This is how all the components are rendered and your React App starts working.
I'm starting to learn react and getting a problem when calling multiple ReactDOM.render functions:
react:
class Header extends React.Component{
render(){
return(
<div>
<p>Test1</p>
</div>
)
}
};
class Main extends React.Component {
render(){
return(
<section>
<p>Test2</p>
</section>
)
}
};
ReactDOM.render(<Main />, document.getElementById('root2'));
ReactDOM.render(<Header />, document.getElementById('root'));
html part:
<body>
<div id="root"></div>
<div id="root2"></div>
</body>
I'm getting the error:
Target container is not a DOM element.
When searching for this problem I got the information that it should be possible to call ReactDom.render multiple times. So I appreciate your help!
Edit: Just tried it with one html tag and changed the id. It seems to have a problem when the id is not "root"...
You are right, you should be able to call render multiple times in your code.
But instead of doing that why don't you do this:
Class App extends Component {
render(){
<React.Fragment>
<Header />
<Main />
</React.Fragment>
}
}
ReactDOM.render(<App />, document.getElementById('root'))
This is easier, correct and performance superior.
I really see no reason as to why soomeone woudld need to put 2 different renderers on one page. Its just putting more strain on the browser for no reason and it will slow down your application.
I want build a React component like
class MyComponent extends React.Component {
render(){
return (<div>This is a simple component</div>);
}
}
and use it like
<MyComponent></MyComponent>
in several different pages and even multiple times in a single html page.
I dont want to create a SPA just to enhance my web application's UI with React components.
Use
ReactDOM.render(<MyComponent />, document.getElementById('id'));
You can render in your HTML like this:
<div id="id"></div>
What you are asking for is not possible right now with React, you want to use what is known as web components.
https://webdesign.tutsplus.com/articles/how-to-create-your-own-html-elements-with-web-components--cms-21524
Read this to learn how to.
The other method is obviously
ReactDOM.render(<MyComponent />, document.getElementById('id'));
If you have to stick with React.
In index.jsx change the typical search for element root getElementById and change the logic to a getElementsByTagName scheme.
let elements=document.getElementsByTagName('MyComponent');
for (element of elements){
ReactDOM.render( <MyComponent />, element );
}
Simply adding React components into HTML code is not possible, because <MyComponent></MyComponent> is not HTML at all, it is JSX.
Explaination
JSX is a special syntax that can be 'transpiled' to Javascript, so in essence <MyComponent></MyComponent> will end up beeing Javascript code, which obviously can not just be put into HTML code.
The Javascript code generated from JSX then will be executed and generates actual HTML code.
It is possible to add HTML tags into JSX, because HTML can be interpreted as JSX (and will be transpiled to Javascript as well), like:
class MyComponent extends React.Component {
render(){
return <div>
<h2>HTML in JSX works</h2>
<SomeOtherJsxComponent />
</div>;
}
}
But it is not possible to add JSX into HTML, like:
<body>
<div>
<JsxInHtmlDoesNotWork />
</div>
</body>
React is Javascript, so everything that is necessary to add Javascript functionality to HTML also applies to adding React to HTML.
(nearest) Solution
So what you could do is to move your existing HTML into to some JSX wrapper (which is probably not what you would like to do, because this goes in the direction of creating a SPA, what you don't want), e.g.:
<html><head>
<title>My web site</title>
</head><body>
<h1>Some HTML title</h1>
<p>Some HTML content.</p>
<!-- add a container, where you want to include react components -->
<div id="injected-react-content"></div>
<!-- import the react libraray -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<!-- setup react root component other components -->
<script type="text/babel">
class RootComponent extends React.Component {
render(){
return <div>
<MyComponent />
</div>;
}
}
class MyComponent extends React.Component {
render(){
return (<div>This is a simple component</div>);
}
}
const domContainer = document.querySelector('#injected-react-content');
ReactDOM.render( React.createElement(RootComponent), domContainer );
</script>
</body></html>
For some more background information on how to add React to an existing HTML website, see e.g.:
stackoverflow.com/questions/65917670/how-to-use-react-components-as-part-of-legacy-html-js-app
stackoverflow.com/questions/69607103/react-component-not-displayed-in-html
There are couple of options which can be explored here
parcel bundle
https://javascriptpros.com/creating-react-widgets-embedded-anywhere/
direflow bundle
https://jhinter.medium.com/using-react-based-web-components-in-wordpress-f0d4097aca38
I'm trying to render a react component inside a html page. what i did so far is implementing react like this
var component = React.createClass({
render: function(){
var testStyle = { fontSize: '18px', marginRight: '20px'};
return (
<div>
<h1>Hello React</h1>
<div><ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul></div>
</div>
)
}
});
ReactDOM.render(< component/>,
document.getElementById('content')
);
and in the HTML page i have this
<div id="content"></div>
when i inspect the HTMl page i find that inside the div i have an empty component like this
<component data-reactroot=""></component>
what am i doing wrong here
A React component must always start with a capital letter, otherwise React interprets it as a simple HTML element.
Capitalized types indicate that the JSX tag is referring to a React component.
That being said, define
const Component = React.createClass...
and then render like
ReactDOM.render(<Component />,
document.getElementById('content')
);