I am using RESTool (https://github.com/dsternlicht/RESTool) as an API-UI and I need to run a js-script after React has rendered everything. window.onload and $(document).ready do not work.
I am assuming you are using react function components.
For every side effect happening after rendering use the useEffect-hook (have a read in the docs if you dont know it, you will need it very often). Then you can dynamically import your script and use it in the hook. In the I have included a network request to load the script in case you dont serve it by your own.
function Component() {
useEffect(() => {
// This happens after rendering with a script requested from an API
makeAPIRequest.then((script) => script.doThisAndThat())
// This assumes you have your script locally, then you can import it dynamically to speed up initial render. Note that when dynamically importing you must default export the script
import('./myScriptThatShouldExecuteAfterRender').then((script) => script.doThis())
})
render(
<SomeThing />
)
}
You can also just import your script normally and then execute it in the useEffect. The dynamic import is just to load the script after you have rendered something to the user and to improve UX.
Related
I'm trying to set up a datatable in my react app and I'd like to do the following
Here's how the documentation for the datatable is doing it:
<script src="plugins/table/datatable/datatables.js"></script>
<script>
$('#dt').DataTable({
"stripeClasses": [],
"pageLength": 7
});
</script>
I tried doing it in react via
import ../plugins/table/datatable/datatables.js"
I also used the method, where you create a script element and append in to the document.body, but both methods seem to return the index.html of my app.
I've read that it's due to React's way of handling requests - I've done an API and I can successfully hit it, however I'm not familiar how to import local files sucessfully. I've also tried importing the files inside the index.html file, but the result is still the same.
I've got a (small) React app (vanilla create-react-app), that I would like to appear in a modal (bootstrap or similar) on another site. Is there a library that will simplify this process?
Specifically, the entire use case is that if my Javascript file is loaded (and just one javascript file), it will insert a "Click Me" type call to action, and when clicked my App component will be loaded into a new modal. It will need the CSS (for the app) to be included in some form as well.
I think all of this (excluding the call-to-action which is fairly simple) could be done during Babel/Webpack transpilation but I can't find anything off-the-shelf that seems to do this.
This functionality is built into ReactDOM.render. Simply add an id to your element.
For example:
<!-- index.html -->
<script src="url/to/react/build/asset" as="script" />
<div id="button-and-modal"></div>
Then to render your react app inside the div:
// index.js
import { render } from 'react-dom';
import App from './App'
function renderReact() {
const element = document.getElementById('button-and-modal');
render(<App/>, element)
}
document.addEventListener('DOMContentLoaded', renderReact);
Then your react app would look something like this:
const App = () => (
<div>
<Button/>
<Modal/>
</div>
)
You can also code the button and modal outside of the react app and only have the modal content rendered by react. If you want to do that, then follow the same directions but add the javascript for the button+modal inside the renderReact function.
You can use for example https://direflow.io/ to build your react app as a web component that you can render anywhere on any site.
Using your current project you can do
direflow create
cd <project-name>
npm install
and then
copy your whole app in folder into direflow-components so your project tree would look like:
/public
/src
/direflow-components
/<project-name>
// leave here only index.ts from example and copy all your project files here
index.ts
component-exports.ts
index.ts
react-app-env.d.ts
.eslintrc
...
If needed you can change
...
component: App,
configuration: {
tagname: 'example-component',
},
...
to your component that you want to render and tagname by which app will be accessible.
After all that you just do
npm run build
copy direflowBundle.js from build folder to your website
and render your app on some website like so:
<body>
<script src="./direflowBundle.js"></script>
<awesome-component></awesome-component>
</body>
I feel like I deal with this issue at every Front End job. It's definitely not easy, but I've found a number of ways to do it. I've tried the bundling idea you suggested but that one gave me the hardest time. The easiest way imo without a lot of hassle is to host your react app on a blank web page, then load it into an iframe where you need it.
At my last job, we wanted to migrate our shopify website to react, but with the way the shopify architecture was set up at the time, it made it difficult to us host a server-side rendered react app. So we built the web pages using Next.js and then deployed it to Vercel. We then inserted this as an iframe into the shopify website. It worked beautifully.
I want to build a SPA on the client site, which supports a plugin concept.
You should be able to copy a package inside a specific folder and the server should load this component after a restart. This plugin should work without any information stored inside the base program.
I need to dynamically load a component by name. I do not have a map of all possible components. How can I load a component by only knowing its name?
you can check out React.lazy. This helps with dynamic loading components which you want, but with this you need to wrap it to Suspense, because component will load not immediately.
// This component is loaded dynamically
const SomeComponent = React.lazy(() => import('./SomeComponent'));
<Suspense fallback={<Spinner/>}><SomeComponent/></Suspense>
Let's assume we have a website, that should show a reactjs application.
The following points are necessary:
The ReactJS application should be embedded by using a short snippet (script / html)
The ReactJS app should be updated without changing the snippet itself
The ReactJS app is hosted on a completely different server
It should not be an iFrame if possible
So what I want to achieve is similary to a Google Map for instance. You have a small snippet and you can show an application on your side.
What are the best practices to do so ? What do I have to take into consideration ?
"Micro frontends":
https://medium.com/#tomsoderlund/micro-frontends-a-microservice-approach-to-front-end-web-development-f325ebdadc16
I came across this idea only recently. So, I don't have much to tell you regarding your requirements. But it looks promising. But also may be an overkill.
And by following links you'll be able to find some code examples.
E.g. https://single-spa.js.org/docs/examples/
simple example without iframe
<script>
(function(window,document, id, scriptUrl, appId){
// create container where to render app
var containerDiv = document.createElement("DIV");
containerDiv.id=appId
document.getElementById(id).appendChild(node);
// add script tag
var scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = scriptUrl;
document.body.appendChild(scriptTag);
// also you may need to send you app info about where should render (id)
window.MY_WIDGET_ID = appId
})(window,document, 'where-to-render-app-id', 'script-url', 'app-id');</script>
<script >
// inside your react app you should add
render( document.getElementById(window.MY_WIDGET_ID ))
A regular React application is a set of JS(let's ignore the CSS, images, other assets this time) files. And there is a file called the entry which mounts the entire application to a specific dom. You might be familiar with the below code.
ReactDOM.render(<App/>, document.getElementById('app'))
The above code is auto executed usually once the entry is loaded onto a predefined dom. We can expose it as an initial handler of the application.
window.apps = {} // This better be executed in a script hosted by the website
window.apps['my-app'] = dom => ReactDOM.render(<App/>, dom)
The script hosted by the website then is able to start the application by calling the function above.
window.apps['my-app'](document.getElementById('root'))
In this way, the website takes the control of initial a React application, at any time, onto any dom, or even any instance.
ps. Ignore type checks, null checks. You should add it as you need to make sure no runtime error happens.
As an other option, you could wrap your react app into web component. Here's the example. But it could be overengineering, from case to case, mpc's approach could be more reasonable easily.
you can create a shell app that will load your remote code and run it.
btw, check out fronty, it is a micro-frontend tool that can help you with that with no hassle.
This is one of the feature React offers. If you take the Basic files provided by React it is an HTML page with a <div id="root"></div>. By default, React is built as a single page App. In fact, you can edit directly this HTML file (located in Public folder) and the React will still run.
So to achieve what you are looking for, build your React project include it to your HTML project (The same include present in the public/index.html -> <script src="/static/js/main.******.chunk.js"></script>.
In the React project, you add the same render condition:
if (document.getElementById("root")) {
ReactDOM.render(
<App />
document.getElementById("root")
);
}
Wrapping the ReactDom.render in an if is to make sure the desired ID is present in your dom.
That's it, it should be working.
Have fun.
I am trying to insert a javascript embed that will load an external script. I am doing it like this:
class Live extends Component {
componentWillMount() {
this.setState({ stream: '<script src="https://content.jwplatform.com/players/CcXHdSyi-r6Pl0rxU.js"></script>' });
}
render() {
return (
<div>
<div contentEditable='true' dangerouslySetInnerHTML={{ __html: this.state.stream }}></div>
</div>
);
}
}
The error I am getting is:
warning.js?85a7:35 Warning: React attempted to reuse markup in a
container but the checksum was invalid. This generally means that you
are using server rendering and the markup generated on the server was
not what the client was expecting. React injected new markup to
compensate which works but you have lost many of the benefits of
server rendering. Instead, figure out why the markup being generated
is different on the client or server: (client) "
data-reactid="1">
Why is this happening?
You get pretty extensive answer by React ;)
...you are using server rendering and the markup generated on the server was not what the client was expecting
This is not an error but warning. At first html markup is generated on Node server and then sent to the browser. Then in browser react renders page again and tries to reuse markup that has already been sent by a server. If there are differences between them - it prints this warning and uses markup generated on client disregarding what has been sent by server.
React injected new markup to compensate which works but you have lost many of the benefits of server rendering.
I'm not sure but if you change componentDidMount to componentWillMount then it may help, as because your script tag will get set on the server as well.
If you are not sure how to properly deal with this I advice you to use library like react-helmet which deals with cases like this. Or maybe you are using Next.js? they have their own way to do it.
Try
componentWillMount() {
this.setState(
{ stream: require( '/path/to/your/script/players/CcXHdSyi-r6Pl0rxU'),
}); }