React HtmlElement Micro Front end is not reloading in Shell Application - javascript

I am trying to inject below react mfe into another angular shell application. But, it is loading first time, but when they hide or remove from dom and then again it is not able to load.
Can you please help what is wrong in below code so that they can reload or hide/show properly.
Thanks in advance.
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import AchPayment from "./AchPayment";
//import createCustomElement from "react-custom-element-builder";
const mount = (el, props) => {
const { consumerName, token, achTransactionRequest } = props;
const root = createRoot(el!);
if (consumerName) {
if (
consumerName.toUpperCase() == "APEX" ||
consumerName.toUpperCase() == "MYFINANCING"
) {
class AchPaymentElement extends HTMLElement {
connectedCallback() {
root.render(
<div>
<AchPayment {...props} />
</div>
);
}
}
customElements.get("ach-payment-element") ||
customElements.define("ach-payment-element", AchPaymentElement);
} else {
return root.render(<h1>Invalid Consumer !</h1>);
}
} else {
return root.render(<h1>Invalid Consumer !</h1>);
}
};
const props = {
consumerName: "MyFinancing",
};
const devRoot = document.querySelector("#_myMfe");
mount(devRoot, props);

i recommend this approach, might help
https://github.com/module-federation/module-federation-examples/tree/master/angular14-react
more documentation you can find here https://webpack.js.org/concepts/module-federation/

Related

Access data from onmessage function from a websocket in Reactjs

I have established a websocket connect from my server to my client machine. I have parsed the data into an object and would like to access the data for representation on my front end.
import './App.css';
import { w3cwebsocket as W3CWebSocket } from "websocket";
import { Component } from 'react';
const client = new W3CWebSocket('ws://xyz:9080/user');
class App extends Component {
componentDidMount() {
client.open = () => {
console.log("Connected");
};
client.onmessage = (e) => {
const object = JSON.parse(e.data);
console.log(object.Snapshot);
}
client.onclose = () => {
console.log("Closed...");
}
}
render() {
return (<div className="App">
<h2>{ object }</h2>
</div>
);
}
}
export default App;
I want to access my object variable from the on message function and use it as a variable in my render function. How do I approach this?
You need to add local state to your class. State is a fairly foundational part of react and how it is able to reactively rerender components, so it sounds like you need to spend some time reading the docs to familiarize yourself with the basics.
That said, I'll provide an updated version of your code for demonstration purposes. Note that you used client.open when you meant client.onopen, so I've made that correction below:
import "./App.css";
import { w3cwebsocket as W3CWebSocket } from "websocket";
import { Component } from "react";
const client = new W3CWebSocket("ws://xyz:9080/user");
class App extends Component {
constructor(props) {
super(props);
this.state = { object: "" };
}
componentDidMount() {
client.onopen = () => {
console.log("Connected");
};
client.onmessage = (e) => {
const object = JSON.parse(e.data);
this.setState({ object: object });
console.log(object.Snapshot);
};
client.onclose = () => {
console.log("Closed...");
};
}
render() {
return (
<div className="App">
<h2>{this.state.object}</h2>
</div>
);
}
}
export default App;
Also, since it seems that you're probably just starting out with react, I would strongly recommend that instead of the old-style class-based components, you use learn to use hooks and functional components, which is just an overall much cleaner and easier to reason about way to write react code. We could rewrite your code as follows using the useState and useEffect hooks in an App function:
import "./App.css";
import { w3cwebsocket as W3CWebSocket } from "websocket";
import { useEffect, useState } from "react";
export default function App() {
const [object, setObject] = useState("");
useEffect(() => {
const client = new W3CWebSocket("ws://xyz:9080/user");
client.onopen = () => {
console.log("Connected");
};
client.onmessage = (e) => {
const newObj = JSON.parse(e.data);
setObject(newObj);
console.log(newObj.Snapshot);
};
client.onclose = () => {
console.log("Closed...");
};
return () => client.OPEN && client.close();
}, []);
return (
<div className="App">
<h2>{object}</h2>
</div>
);
}
Note per the docs that useEffect with an empty dependency array is more or less equivalent to componentDidMount. Note also that even though client is defined in a local scope, it won't be garbage-collected, because it is referenced in the cleanup closure (the return value of the arrow function passed to useEffect).
Finally, note that I haven't used the websocket package before, so I don't know if your usage is correct or optimal. This answer is about how to manage state in react, not how to use websocket in a react application.

Xterm.js: How to hide xterm-helper-textarea?

I try to use Xtermjs in Reactjs. but when I follow the guide. the result shows as following:
It should show without top textarea and text 'W'.
My codes is as following:
import React from 'react';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
class XTerminal extends React.Component {
componentDidMount() {
const {id} = this.props;
const terminalContainer = document.getElementById(id);
const terminal = new Terminal({cursorBlink: true});
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(terminalContainer);
terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
fitAddon.fit();
}
render() {
return(
<div id={this.props.id}></div>
)
}
}
export default XTerminal;
I seach a similar question in stackoverflow without no answer. and I cannot comment in that question. So I write this question. Could anyone help? thanks :)
Finally I got this. For those who have this problem. you should import xterm css style file. like following:
import React from 'react';
import { Terminal } from 'xterm';
import './xterm.css';
import { FitAddon } from 'xterm-addon-fit';
class XTerminal extends React.Component {
componentDidMount() {
const {id} = this.props;
const terminalContainer = document.getElementById(id);
const terminal = new Terminal({cursorBlink: true});
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(terminalContainer);
terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
fitAddon.fit();
}
render() {
return(
<div id={this.props.id}></div>
)
}
}
export default XTerminal;

Test conditionals and useEffect in React with Jest

I need to write a test with the following steps:
get user data on mount
get project details if it has selectedProject and clientId when they change
get pages details if it has selectedProject, clientId, and selectedPages when they change
render Content inside Switch
if doesn't have clientId, Content should return null
if doesn't have selectedProject, Content should return Projects
if doesn't have selectedPages, Content should return Pages
else Content should render Artboard
And the component looks like this:
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getUserData } from "../../firebase/user";
import { selectProject } from "../../actions/projects";
import { getItem } from "../../tools/localStorage";
import { getProjectDetails } from "../../firebase/projects";
import { selectPages } from "../../actions/pages";
import Pages from "../Pages";
import Projects from "../Projects";
import Artboard from "../Artboard";
import Switch from "../Transitions/Switch";
import { getUserId, getClientId } from "../../selectors/user";
import { getSelectedProject } from "../../selectors/projects";
import { getSelectedPages, getPagesWithDetails } from "../../selectors/pages";
import { getPagesDetails } from "../../firebase/pages";
const cachedProject = JSON.parse(getItem("selectedProject"));
const cachedPages = JSON.parse(getItem("selectedPages"));
const Dashboard = () => {
const dispatch = useDispatch();
const userId = useSelector(getUserId);
const clientId = useSelector(getClientId);
const selectedProject = useSelector(getSelectedProject) || cachedProject;
const selectedPages = useSelector(getSelectedPages) || cachedPages;
const pagesWithDetails = useSelector(getPagesWithDetails);
useEffect(() => {
dispatch(
getUserData(userId)
);
cachedProject && selectProject(cachedProject);
cachedPages && selectPages(cachedPages);
}, []);
useEffect(() => {
if (selectedProject && clientId) {
dispatch(
getProjectDetails(
clientId,
selectedProject
)
);
}
}, [selectedProject, clientId]);
useEffect(() => {
if (selectedPages && selectedProject && clientId) {
const pagesWithoutDetails = selectedPages.filter(pageId => (
!Object.keys(pagesWithDetails).includes(pageId)
));
dispatch(
getPagesDetails(
selectedProject,
pagesWithoutDetails
)
);
}
}, [selectedPages, selectedProject, clientId]);
const Content = () => {
if (!clientId) return null;
if (!selectedProject) {
return <Projects key="projects" />;
}
if (!selectedPages) {
return <Pages key="pages" />;
}
return <Artboard key="artboard" />;
};
console.log("Update Dashboard")
return (
<Switch>
{Content()}
</Switch>
);
};
Where I use some functions to fetch data from firebase, some to dispatch actions, and some conditionals.
I'm trying to get deep into testing with Jest and Enzyme. When I was searching for testing approaches, testing useEffect, variables, and conditions, I haven't found anything. All I saw is testing if a text changes, if a button has get clicked, etc. but what about testing components which aren't really changing anything in the DOM, just loading data, and depending on that data, renders a component?
What's the question here? What have you tried? To me it seems pretty straightforward to test:
Use Enzymes mount or shallow to render the component and assign that to a variable and wrap it in a store provider so it has access to a redux store.
Use jest.mock to mock things you don't want to actually want to happen (like the dispatching of actions) or use something like redux-mock-store.
Use that component ".find" to get the actual button you want.
Assert that, given a specific redux state, it renders correctly.
Assert that actions are dispatched with the proper type and payload at the proper times.
You may need to call component.update() to force it to rerender within the enzyme test.
Let me know if you have more specific issues.
Good luck!

How to use deeplearn.js in a React component

I am currently working on creating a project with react and deeplearn.js, and have reached a roadblock when combining the two. In my react application I am importing this deeplearnjs library model which I am using to do classification. Unfortunately, when I try to call the predict() method I get the following error:
TypeError: _this.variables is undefined
For the following part of code:
SqueezeNet.prototype.predictWithActivation = function (input, activationName) {
var _this = this;
var _a = this.math.scope(function () {
var activation;
var preprocessedInput = _this.math.subtract(input.asType('float32'), _this.preprocessOffset);
When I use the generated Javascript in a normal HTML it works perfectly, so I am unsure why I am getting this error within react. I have a feeling it has to do with stricter React rules or Javascript versioning, but I am not sure.
Thanks!
UPDATE
The simplest way to reproduce this is the following:
Create a new React app with create-react-app
Run yarn add deeplearn and yarn add deeplearn-squeezenet
Modify App.js to the following:
import React, { Component } from 'react';
import {ENV, Array3D} from 'deeplearn';
import {SqueezeNet} from 'deeplearn-squeezenet';
class App extends Component {
constructor() {
super();
var net = new SqueezeNet(ENV.math);
net.load();
var img = new Image(227, 227);
img.src = 'boat.jpg';
img.onload = function () {
var pixels = Array3D.fromPixels(img)
var res = net.predict(pixels);
};
}
render() {
return (
<div></div>
);
}
}
export default App;
Download the following file into the public folder: https://raw.githubusercontent.com/PAIR-code/deeplearnjs/master/models/squeezenet/cat.jpg
Run yarn start
For reference I am using react 16.2.0
Your code is presumably failing because some of the method calls are asynchronous (.load() for example).
Here is how you would make your example work with React:
Create a new React app with create-react-app
Run yarn add deeplearn and yarn add deeplearn-squeezenet
Add cat.jpg to the public folder
Modify App.js as below
import React, { Component } from 'react';
import { ENV, Array3D } from 'deeplearn';
import { SqueezeNet } from 'deeplearn-squeezenet';
const math = ENV.math;
const squeezeNet = new SqueezeNet(math);
class App extends Component {
constructor() {
super();
this.state = {
statusText: 'Loading Squeezenet...'
}
}
buildSuggestions(obj){
return Object.keys(obj).map(
key => `${obj[key].toFixed(5)}: ${key}`
);
}
imageLoadHandler(e) {
const img = e.target;
squeezeNet.load()
.then(() => {
this.setState({ statusText: 'Predicting...' });
const pixels = Array3D.fromPixels(img);
const result = squeezeNet.predict(pixels);
this.setState({ statusText: '' });
squeezeNet.getTopKClasses(result, 5)
.then((obj) => {
this.setState({ statusText: this.buildSuggestions(obj) });
});
});
}
render() {
const text = Array.isArray(this.state.statusText)?
this.state.statusText :
[this.state.statusText];
return (
<div>
<img src="cat.jpg"
alt="cat"
onLoad={this.imageLoadHandler.bind(this)}
/>
<div id="result">
{ text.map(el => <div key={el}>{el}</div>) }
</div>
</div>
);
}
}
export default App;
Then run yarn start

Uncaught error returning Array with map()

I'm building a search engine with React.js, where I can look for GIPHY gifs, using their API. When I type a word in the search bar, I get this error: Uncaught (in promise) TypeError: props.gifs.map is not a function
at GifList (SelectedList.js:19)
The console log returns an array, tough :
import React from 'react';
import GifItem from './SelectedListItem';
const GifList = (props) => {
console.log(props.gifs); // Logs Array in the console
const gifItems = props.gifs.map((image) => { // <=======
return <GifItem key={image.id} gif={image} />
});
return (
<div className="gif-list">{gifItems}</div>
);
};
export default GifList;
How is fetching the gifs:
import React from 'react'; //react library
import ReactDOM from 'react-dom'; //react DOM - to manipulate elements
import './index.css';
import SearchBar from './components/Search';
import GifList from './components/SelectedList';
class Root extends React.Component { //Component that will serve as the parent for the rest of the application.
constructor() {
super();
this.state = {
gifs: []
}
this.handleTermChange = this.handleTermChange.bind(this)
}
handleTermChange(term) {
console.log(term);
let url = 'http://api.giphy.com/v1/gifs/search?q=${term.replace(/\s/g, '+')}&api_key=dc6zaTOxFJmzC';
fetch(url).
then(response => response.json()).then((gifs) => {
console.log(gifs);
console.log(gifs.length);
this.setState({
gifs: gifs
});
});
};
render() {
return (
<div>
<SearchBar onTermChange={this.handleTermChange} />
<GifList gifs={this.state.gifs} />
</div>
);
}
}
ReactDOM.render( <Root />, document.getElementById('root'));
Any help is appreciated! Thanks! :)
As per your comment, props.gifs is an object and props.gifs.data is an array. So you need to write
const gifItems = props.gifs && props.gifs.data && props.gifs.data.map((image) => {
return <GifItem key={image.id} gif={image} />
});

Categories