@gondel/plugin-react
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.1.0](https://github.com/namics/gondel/compare/v1.0.0...v1.1.0) (2020-01-16) | ||
### Features | ||
* **react plugin:** add async linkining support to the gondel react plugin ([b39ca5a](https://github.com/namics/gondel/commit/b39ca5a)) | ||
# [1.0.0](https://github.com/namics/gondel/compare/v0.1.0...v1.0.0) (2019-11-28) | ||
@@ -8,0 +19,0 @@ |
@@ -11,2 +11,2 @@ import React, { Component } from "react"; | ||
} | ||
export declare function createRenderAbleAppWrapper<TConfig>(props: Props<TConfig>): JSX.Element; | ||
export declare function createRenderableAppWrapper<TConfig>(props: Props<TConfig>): JSX.Element; |
@@ -60,5 +60,5 @@ var __extends = (this && this.__extends) || (function () { | ||
export { AppWrapper }; | ||
export function createRenderAbleAppWrapper(props) { | ||
export function createRenderableAppWrapper(props) { | ||
return React.createElement(AppWrapper, __assign({}, props)); | ||
} | ||
//# sourceMappingURL=AppWrapper.js.map |
/** | ||
* This is a plugin which allows a simplified usage of gondel together with react | ||
*/ | ||
import { GondelBaseComponent, GondelComponent } from "@gondel/core"; | ||
import React, { ComponentLifecycle, StatelessComponent, ComponentClass } from "react"; | ||
export declare class GondelReactComponent<State> extends GondelBaseComponent implements ComponentLifecycle<null, State> { | ||
_setInternalState: (config: State) => void | undefined; | ||
App?: StatelessComponent<Readonly<State>> | ComponentClass<Readonly<State>, any>; | ||
state: Readonly<State>; | ||
setState(state: Partial<State>): void; | ||
constructor(ctx: HTMLElement, componentName: string); | ||
/** | ||
* Called immediately before mounting occurs, and before `Component#render`. | ||
* Avoid introducing any side-effects or subscriptions in this method. | ||
*/ | ||
componentWillMount?(): void; | ||
/** | ||
* Called immediately after a compoment is mounted. Setting state here will trigger re-rendering. | ||
*/ | ||
componentDidMount?(): void; | ||
/** | ||
* Called when the component may be receiving new props. | ||
* React may call this even if props have not changed, so be sure to compare new and existing | ||
* props if you only want to handle changes. | ||
* | ||
* Calling `Component#setState` generally does not trigger this method. | ||
*/ | ||
componentWillReceiveProps?(nextProps: Readonly<null>, nextContext: any): void; | ||
/** | ||
* Called to determine whether the change in props and state should trigger a re-render. | ||
* | ||
* `Component` always returns true. | ||
* `PureComponent` implements a shallow comparison on props and state and returns true if any | ||
* props or states have changed. | ||
* | ||
* If false is returned, `Component#render`, `componentWillUpdate` | ||
* and `componentDidUpdate` will not be called. | ||
*/ | ||
shouldComponentUpdate?(nextProps: Readonly<null>, nextState: Readonly<State>, nextContext: any): boolean; | ||
/** | ||
* Called immediately before rendering when new props or state is received. Not called for the initial render. | ||
* | ||
* Note: You cannot call `Component#setState` here. | ||
*/ | ||
componentWillUpdate?(nextProps: Readonly<null>, nextState: Readonly<State>, nextContext: any): void; | ||
/** | ||
* Called immediately after updating occurs. Not called for the initial render. | ||
*/ | ||
componentDidUpdate?(prevProps: Readonly<null>, prevState: Readonly<State>, prevContext: any): void; | ||
/** | ||
* Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as | ||
* cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`. | ||
*/ | ||
componentWillUnmount?(): void; | ||
/** | ||
* Catches exceptions generated in descendant components. Unhandled exceptions will cause | ||
* the entire component tree to unmount. | ||
*/ | ||
componentDidCatch?(error: Error, errorInfo: React.ErrorInfo): void; | ||
render(): any; | ||
} | ||
/** React hook to use Gondel components inside React */ | ||
export declare function useGondelComponent<TComponentType extends GondelComponent>(): readonly [(element: HTMLElement | null) => void, TComponentType | null]; | ||
export { useGondelComponent } from "./hooks"; | ||
export { GondelReactComponent } from "./GondelReactComponent"; |
@@ -1,118 +0,6 @@ | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
/** | ||
* This is a plugin which allows a simplified usage of gondel together with react | ||
*/ | ||
import { GondelBaseComponent, startComponents, stopComponents, getComponentByDomNode, hasMountedGondelComponent } from "@gondel/core"; | ||
import React, { useCallback, useRef, useState, useEffect } from "react"; | ||
import { createRenderAbleAppWrapper } from "./AppWrapper"; | ||
/** | ||
* Returns true if the given object is promise like | ||
*/ | ||
function isPromise(obj) { | ||
return obj !== undefined && obj.then !== undefined; | ||
} | ||
var GondelReactComponent = /** @class */ (function (_super) { | ||
__extends(GondelReactComponent, _super); | ||
function GondelReactComponent(ctx, componentName) { | ||
var _this = _super.call(this, ctx, componentName) || this; | ||
// Overwrite the current start method | ||
var originalStart = _this.start; | ||
var ReactDOMPromise = import( | ||
/* webpackPrefetch: true, webpackChunkName: 'ReactDom' */ "react-dom").then(function (ReactDOM) { return ReactDOM.default; }); | ||
var configScript = ctx.querySelector("script[type='text/json']"); | ||
_this.state = configScript ? JSON.parse(configScript.innerHTML) : {}; | ||
_this.start = function () { | ||
var _this = this; | ||
// Wait for the original start promise to allow lazy loading | ||
var originalStartPromise = new Promise(function (resolve, reject) { | ||
if (!originalStart) { | ||
return resolve(); | ||
} | ||
if (originalStart.length) { | ||
return originalStart.call(_this, resolve, reject); | ||
} | ||
var result = originalStart.call(_this); | ||
return isPromise(result) ? result.then(resolve, reject) : resolve(result); | ||
}); | ||
// Render the app | ||
var renderAppPromise = originalStartPromise | ||
.then(function () { return ReactDOMPromise; }) | ||
.then(function (ReactDOM) { | ||
// Render only if the app was not stopped | ||
_this._stopped || | ||
ReactDOM.render(createRenderAbleAppWrapper({ | ||
children: _this.render.bind(_this), | ||
onHasState: function (setInternalState) { | ||
_this._setInternalState = setInternalState; | ||
}, | ||
componentWillUnmount: function () { | ||
delete _this._setInternalState; | ||
_this.componentWillUnmount && _this.componentWillUnmount(); | ||
}, | ||
componentDidMount: _this.componentDidMount && _this.componentDidMount.bind(_this), | ||
componentWillReceiveProps: _this.componentWillReceiveProps && _this.componentWillReceiveProps.bind(_this), | ||
shouldComponentUpdate: _this.shouldComponentUpdate && _this.shouldComponentUpdate.bind(_this), | ||
componentWillUpdate: _this.componentWillUpdate && _this.componentWillUpdate.bind(_this), | ||
componentDidUpdate: _this.componentDidUpdate && _this.componentDidUpdate.bind(_this), | ||
componentDidCatch: _this.componentDidCatch && _this.componentDidCatch.bind(_this), | ||
config: _this.state | ||
}), _this._ctx); | ||
}); | ||
return renderAppPromise; | ||
}; | ||
return _this; | ||
} | ||
GondelReactComponent.prototype.setState = function (state) { | ||
this.state = Object.assign({}, this.state, state); | ||
// Handover the state to react | ||
// if the component was already rendered | ||
if (this._setInternalState) { | ||
this._setInternalState(this.state); | ||
} | ||
}; | ||
GondelReactComponent.prototype.render = function () { | ||
if (this.App) { | ||
return React.createElement(this.App, this.state); | ||
} | ||
throw new Error(this._componentName + " is missing a render method"); | ||
}; | ||
return GondelReactComponent; | ||
}(GondelBaseComponent)); | ||
export { GondelReactComponent }; | ||
/** React hook to use Gondel components inside React */ | ||
export function useGondelComponent() { | ||
var _a = useState(null), gondelInstance = _a[0], setGondelInstance = _a[1]; | ||
var ref = useRef(); | ||
var refFunction = useCallback(function (element) { | ||
if (element) { | ||
ref.current = element; | ||
startComponents(element).then(function () { | ||
setGondelInstance(hasMountedGondelComponent(element) ? getComponentByDomNode(element) : null); | ||
}); | ||
} | ||
}, []); | ||
useEffect(function () { | ||
// Cleanup on unmount | ||
return function () { | ||
var element = ref.current; | ||
if (element) { | ||
stopComponents(element); | ||
ref.current = undefined; | ||
} | ||
}; | ||
}, []); | ||
return [refFunction, gondelInstance]; | ||
} | ||
export { useGondelComponent } from "./hooks"; | ||
export { GondelReactComponent } from "./GondelReactComponent"; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@gondel/plugin-react", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Gondel Plugin to boot react widgets and apps", | ||
@@ -14,2 +14,3 @@ "bugs": "https://github.com/namics/gondel/issues", | ||
"scripts": { | ||
"test": "jest", | ||
"build:clean": "rimraf dist", | ||
@@ -29,3 +30,4 @@ "build:esm": "tsc --project ./tsconfig.json --declaration --esModuleInterop --declarationDir dist/ --sourceMap --outDir dist/", | ||
"devDependencies": { | ||
"@gondel/core": "^1.0.0", | ||
"@gondel/core": "^1.1.0", | ||
"jest": "24.9.0", | ||
"npm-run-all": "4.1.5", | ||
@@ -35,5 +37,28 @@ "react": "16.11.0", | ||
"rimraf": "3.0.0", | ||
"typescript": "3.6.2" | ||
"typescript": "3.7.4" | ||
}, | ||
"gitHead": "45edacbe40d1307cf4a7471a85554dba385b144d" | ||
"jest": { | ||
"globals": { | ||
"ts-jest": { | ||
"diagnostics": true | ||
} | ||
}, | ||
"transform": { | ||
"^.+\\.tsx?": "ts-jest" | ||
}, | ||
"testRegex": "\\.test\\.tsx?", | ||
"collectCoverage": true, | ||
"collectCoverageFrom": [ | ||
"src/**/*.{ts,tsx,js,jsx}" | ||
], | ||
"coverageDirectory": "coverage", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"json", | ||
"node" | ||
] | ||
}, | ||
"gitHead": "f5265fead99d39b1b5fee5572e5216c1fcb0a34f" | ||
} |
169
README.md
@@ -7,3 +7,3 @@ # React Plugin | ||
html | ||
**HTML** | ||
@@ -14,3 +14,3 @@ ```html | ||
js | ||
**JavaScript** | ||
@@ -35,6 +35,7 @@ ```js | ||
Most apps need some specific configuration e.g. Api enpoints. | ||
The following pattern allows you to pass a basic configuration from the dom to your app. | ||
Most apps need some specific configuration e.g. API enpoints or other settings. | ||
The following pattern allows you to pass a basic configuration from the DOM to your application. | ||
This guarantees us that we have the full flexibility to pass a configuration, so that it can get rendered by anyone (e.g. CMS). | ||
html | ||
**HTML** | ||
@@ -48,3 +49,3 @@ ```html | ||
js | ||
**JavaScript** | ||
@@ -67,10 +68,12 @@ ```js | ||
## Component linking | ||
## Lazy loading | ||
It's also possible to link a gondel component to a react component without using a render method. | ||
To load the javascript of your react widget only if the matching HTML Element is present you can use | ||
the following pattern: | ||
### Sync linking example | ||
html | ||
In the following example below the React app will be bundled into the same bundle (no code splitting). | ||
**HTML** | ||
```html | ||
@@ -83,49 +86,60 @@ <div data-g-name="DemoWidget"> | ||
js | ||
**JavaScript** | ||
```js | ||
import {GondelReactComponent} from '@gondel/plugin-react'; | ||
import {Component} from '@gondel/core'; | ||
import React from 'react'; | ||
import { GondelReactComponent } from '@gondel/plugin-react'; | ||
import { Component } from '@gondel/core'; | ||
import { App } from './App'; | ||
@Component('DemoWidget') | ||
export class DemoWidget extends GondelReactComponent { | ||
async start() { | ||
this.App = await import('./App').App; | ||
} | ||
render(config) { | ||
const App = this.App; | ||
return | ||
<App config={config} /> | ||
)); | ||
} | ||
App = App; | ||
} | ||
``` | ||
### Lazy linking example (code splitting) | ||
## Component linking | ||
To only lazy load the JavaScript of your React widget if the matching | ||
HTML Element is present, you can use the following pattern below which is called lazy linking: | ||
It's also possible to link a gondel component to a react component without using a render method. | ||
**HTML** | ||
### Sync linking example | ||
```html | ||
<div data-g-name="DemoWidget"> | ||
<script type="text/json">{ "foo":"bar" }</script> | ||
Loading.. | ||
</div> | ||
``` | ||
**JavaScript** | ||
```js | ||
import {GondelReactComponent} from '@gondel/plugin-react'; | ||
import {Component} from '@gondel/core'; | ||
import {App} from './App'; | ||
import React from 'react'; | ||
import { GondelReactComponent } from '@gondel/plugin-react'; | ||
import { Component } from '@gondel/core'; | ||
@Component('DemoWidget') | ||
export class DemoWidget extends GondelReactComponent { | ||
App = App; | ||
App = import('./App').then(({ App }) => App); | ||
} | ||
``` | ||
### Async linking example | ||
### Async blocking linking example (code splitting) | ||
You can use a async start method to lazy load a component and tell Gondel to wait until the JavaScript of the component has been loaded. | ||
This will guarantee that the sync method of all Gondel components will be delayed until the React component was completely loaded. | ||
**HTML** | ||
```html | ||
<div data-g-name="DemoWidget"> | ||
<script type="text/json">{ "foo":"bar" }</script> | ||
Loading.. | ||
</div> | ||
``` | ||
**JavaScript** | ||
```js | ||
import {GondelReactComponent} from '@gondel/plugin-react'; | ||
import {Component} from '@gondel/core'; | ||
import React from 'react'; | ||
import { GondelReactComponent } from '@gondel/plugin-react'; | ||
import { Component } from '@gondel/core'; | ||
@@ -135,3 +149,3 @@ @Component('DemoWidget') | ||
async start() { | ||
this.App = await import('./App').App; | ||
this.App = (await import('./App')).App; | ||
} | ||
@@ -144,16 +158,32 @@ } | ||
It is possible to manipulate the state inside a public method. | ||
Initially the state is load from the script tag inside the components HTML markup. | ||
In the following example below, Gondel would extract the initial state `{ theme: 'light' }`: | ||
```js | ||
import {GondelReactComponent} from '@gondel/plugin-react'; | ||
import {Component} from '@gondel/core'; | ||
import {App} from './App'; | ||
```html | ||
<div data-g-name="DemoWidget"> | ||
<script type="text/json">{ "theme":"light" }</script> | ||
Loading.. | ||
</div> | ||
``` | ||
This initial state can be accessed inside the `GondelReactComponent` using `this.state`. | ||
It is even possible to update the state of the component by calling the method `this.setState(...)`: | ||
```tsx | ||
import React from 'react'; | ||
import { GondelReactComponent } from '@gondel/plugin-react'; | ||
import { Component } from '@gondel/core'; | ||
const DemoApp = ({ theme }) => ( | ||
<h1 className={theme === 'dark' ? 'dark' : 'light'}> | ||
Hello World | ||
</h1> | ||
); | ||
@Component('DemoWidget') | ||
export class DemoWidget extends GondelReactComponent<{counter: number}> { | ||
App = App; | ||
export class DemoWidget extends GondelReactComponent<{theme: 'light' | 'dark'}> { | ||
App = DemoApp; | ||
setCounter(counter: number) { | ||
this.setState({counter}) | ||
setTheme(theme: 'light' | 'dark') { | ||
this.setState({ theme }); | ||
} | ||
@@ -163,8 +193,8 @@ } | ||
With this public method it is now possible to set the counter using | ||
get component by using [`getComponentByDomNode`](https://gondel.js.org/docs/api.html#getcomponentbydomnode-domnode-namespace-gondelbasecomponent): | ||
In the example above we've created a public `setTheme` method which is now a public API for your React widget. | ||
In combination with [`getComponentByDomNode`](https://gondel.js.org/docs/api.html#getcomponentbydomnode-domnode-namespace-gondelbasecomponent) it allows changing the state during runtime by external components: | ||
```js | ||
getComponentByDomNode(domElement).setCounter(10) | ||
getComponentByDomNode(domElement).setTheme('dark') | ||
``` | ||
@@ -174,4 +204,8 @@ | ||
The `useGondelComponent` hook allows to use a Gondel UI component like an accordion or button inside a react app. | ||
The `useGondelComponent` hook allows us to use a Gondel UI component like an accordion or button inside a React app. | ||
This can be really handy if you want to interop with your existing component markup inside of React. | ||
### Example | ||
```js | ||
@@ -188,7 +222,8 @@ import { useGondelComponent } from '@gondel/plugin-react'; | ||
In addition to the `ref` object an instance of the gondel component is returned. | ||
This allows controlling the Gondel component from react. | ||
In addition to the `ref` object, an instance of the Gondel component gets returned. | ||
This allows to fully control the Gondel component from the React code. | ||
```js | ||
// react component | ||
**React component** | ||
```tsx | ||
import { useGondelComponent } from '@gondel/plugin-react'; | ||
@@ -199,13 +234,21 @@ | ||
return ( | ||
<button onClick={() => { | ||
// Ensure that the gondelInstance is already initialized | ||
if (gondelButtonInstance) { | ||
// Execute a class method from the Gondel component | ||
gondelButtonInstance.setIsEnabled(false); | ||
} | ||
}} ref={ref} data-g-name="Button"></button> | ||
<button | ||
ref={ref} | ||
data-g-name="Button" | ||
onClick={() => { | ||
// Ensure that the gondelInstance is already initialized | ||
if (gondelButtonInstance) { | ||
// Execute a class method from the Gondel component | ||
gondelButtonInstance.setIsEnabled(false); | ||
} | ||
}}> | ||
Button text | ||
</button> | ||
); | ||
}; | ||
``` | ||
// gondel component | ||
**Gondel component** | ||
```ts | ||
import { Component, GondelBaseComponent } from '@gondel/core'; | ||
@@ -216,3 +259,3 @@ | ||
setIsEnabled(newState) { | ||
if(newState) { | ||
if (newState) { | ||
this._ctx.removeAttribute('disabled'); | ||
@@ -219,0 +262,0 @@ } else { |
193
src/index.ts
/** | ||
* This is a plugin which allows a simplified usage of gondel together with react | ||
*/ | ||
import { | ||
GondelBaseComponent, | ||
GondelComponent, | ||
startComponents, | ||
stopComponents, | ||
getComponentByDomNode, | ||
hasMountedGondelComponent | ||
} from "@gondel/core"; | ||
import React, { | ||
ComponentLifecycle, | ||
StatelessComponent, | ||
ComponentClass, | ||
useCallback, | ||
useRef, | ||
useState, | ||
useEffect | ||
} from "react"; | ||
import { createRenderAbleAppWrapper } from "./AppWrapper"; | ||
/** | ||
* Returns true if the given object is promise like | ||
*/ | ||
function isPromise<T>(obj: {} | Promise<T> | undefined | string | number): obj is Promise<T> { | ||
return obj !== undefined && (<Promise<T>>obj).then !== undefined; | ||
} | ||
export class GondelReactComponent<State> extends GondelBaseComponent | ||
implements ComponentLifecycle<null, State> { | ||
_setInternalState: (config: State) => void | undefined; | ||
App?: StatelessComponent<Readonly<State>> | ComponentClass<Readonly<State>, any>; | ||
state: Readonly<State>; | ||
setState(state: Partial<State>) { | ||
this.state = Object.assign({}, this.state, state); | ||
// Handover the state to react | ||
// if the component was already rendered | ||
if (this._setInternalState) { | ||
this._setInternalState(this.state); | ||
} | ||
} | ||
constructor(ctx: HTMLElement, componentName: string) { | ||
super(ctx, componentName); | ||
// Overwrite the current start method | ||
const originalStart = (this as any).start; | ||
const ReactDOMPromise = import( | ||
/* webpackPrefetch: true, webpackChunkName: 'ReactDom' */ "react-dom" | ||
).then(ReactDOM => ReactDOM.default); | ||
const configScript = ctx.querySelector("script[type='text/json']"); | ||
this.state = configScript ? JSON.parse(configScript.innerHTML) : {}; | ||
(this as any).start = function(this: GondelReactComponent<State>) { | ||
// Wait for the original start promise to allow lazy loading | ||
const originalStartPromise = new Promise((resolve, reject) => { | ||
if (!originalStart) { | ||
return resolve(); | ||
} | ||
if (originalStart.length) { | ||
return originalStart.call(this, resolve, reject); | ||
} | ||
const result = originalStart.call(this); | ||
return isPromise(result) ? result.then(resolve, reject) : resolve(result); | ||
}); | ||
// Render the app | ||
const renderAppPromise = originalStartPromise | ||
.then(() => ReactDOMPromise) | ||
.then(ReactDOM => { | ||
// Render only if the app was not stopped | ||
this._stopped || | ||
ReactDOM.render( | ||
createRenderAbleAppWrapper({ | ||
children: this.render.bind(this), | ||
onHasState: setInternalState => { | ||
this._setInternalState = setInternalState; | ||
}, | ||
componentWillUnmount: () => { | ||
delete this._setInternalState; | ||
this.componentWillUnmount && this.componentWillUnmount(); | ||
}, | ||
componentDidMount: this.componentDidMount && this.componentDidMount.bind(this), | ||
componentWillReceiveProps: | ||
this.componentWillReceiveProps && this.componentWillReceiveProps.bind(this), | ||
shouldComponentUpdate: | ||
this.shouldComponentUpdate && this.shouldComponentUpdate.bind(this), | ||
componentWillUpdate: | ||
this.componentWillUpdate && this.componentWillUpdate.bind(this), | ||
componentDidUpdate: this.componentDidUpdate && this.componentDidUpdate.bind(this), | ||
componentDidCatch: this.componentDidCatch && this.componentDidCatch.bind(this), | ||
config: this.state | ||
}), | ||
this._ctx | ||
); | ||
}); | ||
return renderAppPromise; | ||
}; | ||
} | ||
/** | ||
* Called immediately before mounting occurs, and before `Component#render`. | ||
* Avoid introducing any side-effects or subscriptions in this method. | ||
*/ | ||
componentWillMount?(): void; | ||
/** | ||
* Called immediately after a compoment is mounted. Setting state here will trigger re-rendering. | ||
*/ | ||
componentDidMount?(): void; | ||
/** | ||
* Called when the component may be receiving new props. | ||
* React may call this even if props have not changed, so be sure to compare new and existing | ||
* props if you only want to handle changes. | ||
* | ||
* Calling `Component#setState` generally does not trigger this method. | ||
*/ | ||
componentWillReceiveProps?(nextProps: Readonly<null>, nextContext: any): void; | ||
/** | ||
* Called to determine whether the change in props and state should trigger a re-render. | ||
* | ||
* `Component` always returns true. | ||
* `PureComponent` implements a shallow comparison on props and state and returns true if any | ||
* props or states have changed. | ||
* | ||
* If false is returned, `Component#render`, `componentWillUpdate` | ||
* and `componentDidUpdate` will not be called. | ||
*/ | ||
shouldComponentUpdate?( | ||
nextProps: Readonly<null>, | ||
nextState: Readonly<State>, | ||
nextContext: any | ||
): boolean; | ||
/** | ||
* Called immediately before rendering when new props or state is received. Not called for the initial render. | ||
* | ||
* Note: You cannot call `Component#setState` here. | ||
*/ | ||
componentWillUpdate?( | ||
nextProps: Readonly<null>, | ||
nextState: Readonly<State>, | ||
nextContext: any | ||
): void; | ||
/** | ||
* Called immediately after updating occurs. Not called for the initial render. | ||
*/ | ||
componentDidUpdate?( | ||
prevProps: Readonly<null>, | ||
prevState: Readonly<State>, | ||
prevContext: any | ||
): void; | ||
/** | ||
* Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as | ||
* cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`. | ||
*/ | ||
componentWillUnmount?(): void; | ||
/** | ||
* Catches exceptions generated in descendant components. Unhandled exceptions will cause | ||
* the entire component tree to unmount. | ||
*/ | ||
componentDidCatch?(error: Error, errorInfo: React.ErrorInfo): void; | ||
render(): any { | ||
if (this.App) { | ||
return React.createElement(this.App, this.state); | ||
} | ||
throw new Error(`${this._componentName} is missing a render method`); | ||
} | ||
} | ||
/** React hook to use Gondel components inside React */ | ||
export function useGondelComponent<TComponentType extends GondelComponent>() { | ||
const [gondelInstance, setGondelInstance] = useState<TComponentType | null>(null); | ||
const ref = useRef<HTMLElement | undefined>(); | ||
const refFunction = useCallback((element: HTMLElement | null) => { | ||
if (element) { | ||
ref.current = element; | ||
startComponents(element).then(() => { | ||
setGondelInstance( | ||
hasMountedGondelComponent(element) ? getComponentByDomNode<TComponentType>(element) : null | ||
); | ||
}); | ||
} | ||
}, []); | ||
useEffect(() => { | ||
// Cleanup on unmount | ||
return () => { | ||
const element = ref.current; | ||
if (element) { | ||
stopComponents(element); | ||
ref.current = undefined; | ||
} | ||
}; | ||
}, []); | ||
return [refFunction, gondelInstance] as const; | ||
} | ||
export { useGondelComponent } from "./hooks"; | ||
export { GondelReactComponent } from "./GondelReactComponent"; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
54758
28
920
255
7
1