Open geanrt opened 1 year ago
I also remember that I used Jquery to help me with production speed, but can you find a way without using jquery, how to identify it when we want to inject a React component into the host content and convert it somehow to an injectable block.
This code has a problem, the component's internal functions don't work, so it's not useful... I'll try to develop a better way then.
import React from "react";
import $ from "jquery";
import {createRoot} from "react-dom/client";
$.fn.reactAppend = async function (component) {
return this.each(function () {
const container = document.createElement("div");
const root = createRoot(container);
root.render(<React.StrictMode>{component}</React.StrictMode>);
$(this).append(container);
});
};
$.fn.reactPrepend = function (component) {
return this.each(function () {
const container = document.createElement("div");
const root = createRoot(container);
root.render(<React.StrictMode>{component}</React.StrictMode>);
$(this).prepend(container);
});
};
I made these modifications, but I intend to bring here an automatic way to inject React components into the Host
You could just inject react on pageLoad and then in the useEffect hook into the elements on the page - thats the flow that im using in all my projects.
You could just inject react on pageLoad and then in the useEffect hook into the elements on the page - thats the flow that im using in all my projects.
How would it be?
Im basically using
import React, { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
export default function SmartPortal({ // i didnt have a better name. Its takem probably from a stackoverflow answer
id,
children,
append = undefined,
style,
}: {
id: string;
children: React.ReactNode;
/* cannot be changed between renders /
append?: (e: HTMLElement) => void;
/* cannot be changed between renders /
style?: Partial
3. Rerender a component hosting it with a MutationObserver - wait for a good host page to inject correctly.
To force update (rerender when mutationObserver detects good host page state) - just change the id/key of the `SmartPortal`
When using this approach you do not lose the react tree (and ContextApi works)
This is very interesting, if we add what I currently have (which works 100%, including the internal functions lol) we will have something very efficient
import React from "react";
import ReactDOM from "react-dom/client";
import $ from "jquery";
// Node `Collector` by XPath
import _x from "./_x";
interface InsertParams {
id: string;
path: string | HTMLElement;
el: React.ReactNode;
insertionMethod: "append" | "prepend" | "after" | "before";
}
class Injector {
private insert({ id, path, el, insertionMethod }: InsertParams) {
const container = $(`<div id="${id}"></div>`);
if (typeof path === "string") $(_x(path))[insertionMethod](container);
if (path instanceof HTMLElement) $(path)[insertionMethod](container);
ReactDOM.createRoot(container[0]).render(<React.StrictMode>{el}</React.StrictMode>);
}
append = (id: string, path: string | HTMLElement, el: React.ReactNode) =>
this.insert({ id, path, el, insertionMethod: "append" });
prepend = (id: string, path: string | HTMLElement, el: React.ReactNode) =>
this.insert({ id, path, el, insertionMethod: "prepend" });
after = (id: string, path: string | HTMLElement, el: React.ReactNode) =>
this.insert({ id, path, el, insertionMethod: "after" });
before = (id: string, path: string | HTMLElement, el: React.ReactNode) =>
this.insert({ id, path, el, insertionMethod: "before" });
}
export default new Injector();
Yeah the Injector
is implementation of the append
function.
In my projects where i inject extension react apps into host page react apps it is sometimes more complex thats why i didnt publish it.
Sometimes it's just insert as a specific column
import { ComponentType } from 'react';
export const XPageInjector = ({SomeRenderPropPlaceholder} : {SomeRenderPropPlaceholder: ComponentType})=>{
return <SmartPortal
id={`SomePlaceholder-${renderId}-${rowId}`}
append={(e) =>document.querySelector("[class*='ClientsTable-module__headerRow'] :nth-child(3)")?.after(e); }
style={{ /** some styles */ }}
>
<SomeRenderPropPlaceholder/>
</SmartPortal>
}
Sometimes it reorganizes the DOM of the host page
<SmartPortal
key={`somepage-injector-${renderId}`}
id={`somepage-injector-${renderId}`}
append={(e) => {
let par = document.querySelector('#some-page-root');
if (par) {
par.prepend(e);
return;
}
let someHostPageButton = getSomeButton();
if (!someHostPageButton) {
return;
}
let originalParent = someHostPageButton?.parentElement;
let newParent = document.createElement('div');
newParent.id = 'some-page-root';
Object.assign(newParent.style, { display: 'flex', alignItems: 'center' });
originalParent?.append(newParent);
Object.assign(e, { style: 'display: flex;' });
newParent.append(e);
newParent.append(someHostPageButton);
}}
>
<SomeRenderPropPlaceholder/>
</SmartPortal>
Describe the problem
I've been studying the module and I didn't see a function to inject a React component into the page's DOM, so I developed a solution and I hope you use it and implement it in the best way!
Describe the proposed solution
we create the root (CH), rederize the component in it, wait until it is available with the Mutation Observer, take the first child node and inject it using conventional Jquery functions into the selected component (this).
utils.jsx
content.jsx (using)
Alternatives considered
Furthermore, I hope they bring me an update and implement this, which is very important for us who create tools and utilities for websites.
Importance
nice to have