How to use deeplearn.js in a React component - javascript

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

Related

Navigo Javascript routing: Every route I register didn't match any of the registered routes

I'm learning how to make a single page app with javascript.
My javascript teacher provided a beautiful tutorial how to create a single page application from scratch. I followed the tutorial and everything went well untill the part where the routing came in..
He uses a library which is called navigo. I don't know why but it seems to not working for me at all.
The moment I've written the final line of code. My homepage disappeared and the console gave a warning that my route '/' which is my homepage, didn't match any of the registered routes, but it looks like there is no route registered at all, while I'm definitly registering them..
here is my code
My root index.js
import './sass/main.scss';
import App from './App';
import { HomeComponent, NewEventComponent } from './Components';
// Retrieve appComponent
const initApp = () => {
const appContainer = document.getElementById('appContainer');
const app = new App(appContainer);
app.addComponent(new HomeComponent());
app.addComponent(new NewEventComponent());
};
window.addEventListener('load', initApp);
My App.js (here is where my route is defined for every component. routerPath makes it dynamic )
// The App Wrapper
import Component from './lib/Component';
import Router from './Router';
class App {
constructor(parent) {
this.parent = parent;
this.components = [];
}
clearparent() {
while (this.parent.firstChild) {
this.parent.removeChild(this.parent.lastChild);
}
}
addComponent(component) {
if (!(component instanceof Component)) return;
// get the name from our component
const { name, routerPath } = component;
// when a component asks to reRender
component.reRender = () => this.showComponent(component);
// add to internal class
this.components.push(component);
// add to router
Router.getRouter().on(routerPath, () => {
this.showComponent({ name });
}).resolve();
}
showComponent({ name }) {
const foundComponent = this.components.find((component) => component.name === name);
if (!foundComponent) return;
this.clearparent();
this.parent.appendChild(foundComponent.render());
}
}
export default App;
The Home Component
// The Home Component
import Component from '../lib/Component';
import Elements from '../lib/Elements';
class HomeComponent extends Component {
constructor() {
super({
name: 'home',
model: {
counter: 0,
},
routerPath: '/',
});
}
incrementCounter() {
this.model.counter += 1;
}
render() {
const { counter } = this.model;
// create home container
const homeContainer = document.createElement('div');
// append header
homeContainer.appendChild(
Elements.createHeader({
textContent: `Current value is: ${counter}`,
}),
);
// append button
homeContainer.appendChild(
Elements.createButton({
textContent: 'increase',
onClick: () => { this.incrementCounter(); },
}),
);
return homeContainer;
}
}
export default HomeComponent;
A Component
// My components
class Component {
constructor({
name,
model,
routerPath,
}) {
this.name = name;
this.model = this.proxyModel(model);
this.routerPath = routerPath;
this.reRender = null;
}
proxyModel(model) {
return new Proxy(model, {
set: (obj, prop, value) => {
obj[prop] = value;
if (this.reRender) this.reRender();
return true;
},
});
}
}
export default Component;
The Router
// My Router
import Navigo from 'navigo';
const Router = {
router: null,
getRouter() {
if (!this.router) {
const rootUrl = `${window.location.protocol}//${window.location.host}`;
this.router = new Navigo(rootUrl, false);
}
return this.router;
},
};
export default Router;
Solution: I switched to Navigo(^7.0.0) and it works!
I seem to have the same problem as you. I'm also using navigo (^8.11.1). The problem is fixed for me when I declare a new router like this: new Navigo('/', false).
It still gives me the warning now, but it loads the page. sadly, this will only work in a dev environment

React HtmlElement Micro Front end is not reloading in Shell Application

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/

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.

reactjs component for uploading csv file to server is not working properly

I am learning reactjs for building web application. Basically, my goal is I want to create reactjs component that can upload local csv file to the server (I created server js). To do so, I come across a basic reactjs component implementation down below:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
var FormBox = React.createClass({
getInitialState: function () {
return {
file: '',
FilePreviewUrl: ''
};
},
pressButton: function () {
e.preventDefault();
console.log('handle uploading-', this.state.file);
},
uploadCSV: function (e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
FilePreviewUrl: reader.result
});
}
reader.readAsDataURL(file);
},
render: function () {
let {FilePreviewUrl} = this.state;
let FilePreview = null;
if (FilePreviewUrl) {
FilePreview = (<img src={FilePreviewUrl} />);
} else {
FilePreview = (<div className="previewText">Please select an Json for Preview</div>);
}
return (
<div>
<form action='.' enctype="multipart/form-data">
<input type='file' onChange={this.uploadCSV}/>
<button onClick={this.pressButton}> Get it </button>
</form>
<div className="filePreview">
{FilePreview}
</div>
</div>
)
}
})
}
ReactDOM.render(<FormBox />, document.getElementById('root'))
export default App;
but when I run my component I got an error which is not intuitive to me. Here is the error:
Failed to compile.
./src/App.js
Line 6: Parsing error: Unexpected token
4 |
5 | class App extends Component {
> 6 | var FormBox = React.createClass({
| ^
7 | getInitialState: function () {
8 | return {
9 | file: '',
How to fix this error? How to make above implementation works for the purpose of uploading csv file to the server? any idea?
clarification:
I am doing this because I intend to upload local csv file to the server and trigger API key that provided at back-end to populate the csv data to the database. I am newbie to reactjs so my above code may not be well shaped. can anyone help me how to make this works? any help would be appreciated.
goal:
Sine few smart people in SO community suggested me that I was wrong about the implementation. What I am actually trying to do is to upload local files to server. How can I modify above code for creating reactjs component for uploading file to server?
So you're mixing up some syntax for declaring React components. Here it is rewritten with a working codesandbox: https://5y03xnvpqx.codesandbox.io/
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class FormBox extends Component {
constructor(props) {
super(props);
this.state = {
file: "",
filePreviewUrl: ""
};
this.pressButton = this.pressButton.bind(this);
this.uploadCSV = this.uploadCSV.bind(this);
}
pressButton(e) {
e.preventDefault();
console.log("handle uploading-", this.state.file);
}
uploadCSV(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
filePreviewUrl: reader.result
});
};
reader.readAsDataURL(file);
}
render() {
const { filePreviewUrl } = this.state;
let FilePreview = null;
if (filePreviewUrl) {
FilePreview = <img src={FilePreviewUrl} />;
} else {
FilePreview = (
<div className="previewText">Please select an Json for Preview</div>
);
}
return (
<div>
<form action="." enctype="multipart/form-data">
<input type="file" onChange={this.uploadCSV} />
<button onClick={this.pressButton}> Get it </button>
</form>
<div className="filePreview">{FilePreview}</div>
</div>
);
}
}
function App() {
return (
<div className="App">
<FormBox />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You'll notice that I put filePreviewUrl in lower case. By convention, React components are uppercase, so when you see something that's uppercase, you expect that it's eventually going to become a component. If that's not the case, best to leave it lowercase.
You are declaring a class inside a class, and you shouldn't use React.CreateClass anymore since its deprecated. Also, you have to import ReactDOM in order to use it (at the bottom of your file).
I don't know why you need the App component, but I editted your code to include the correct syntax (Can't really check the csv upload logic).
I'm assuming that you're using some sort of a request helper library. in this example I use axios.
I don't really know the FileReader api, but if I understand it correctly, onloadend returns the file data. After that we can send the data to the server (where we use axios.post).
The next step would be to define an endpoint on the server (I'm assuming express) that gets the data and saves it to the server using the fs module (HINT: fs.writeFile).
import ReactDOM from 'react-dom';
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';
class App extends Component {
render() {
return (
<FormBox />
)
}
}
class FormBox extends Component {
constructor(props) {
super(props);
this.state = {
file: '',
filePreviewUrl: ''
}
}
uploadCSV(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = (error, data) => {
if (error) throw new Error('Oops! something went wrong!');
axios.post('http://your-link-goes-here/', {data: data}).then(data => {
this.setState({
file: file,
filePreviewUrl: reader.result
});
})
}
reader.readAsDataURL(file);
}
render() {
let {filePreviewUrl} = this.state;
let filePreview = null;
if (filePreviewUrl) {
filePreview = (<img src={filePreviewUrl} />);
} else {
filePreview = (<div className="previewText">Please select an Json for Preview</div>);
}
return (
<div>
<form action='.' enctype="multipart/form-data">
<input type='file' onChange={this.uploadCSV}/>
<button onClick={(e) => this.uploadCSV(e)}> Get it </button>
</form>
<div className="filePreview">
{filePreview}
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))

React- only run file once external js file loaded (gapi not defined)

I am trying to use the gmail API with React.js.
I keep getting the error 'gapi is not defined'. I believe my client.js file in the HTML is loading after my mail.js file runs?
How can I get around this?
Index.html
...
<script src="https://apis.google.com/js/client.js"></script>
Index.js
import './Mail.js';
Mail.js
import { createAction, handleActions } from 'redux-actions'
const CLIENT_ID = '1.apps.googleusercontent.com'
const SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
export const SET_GMAIL_CREDENTIALS = 'SET_GMAIL_CREDENTIALS'
export const CHANGE_LOADING = 'CHANGE_LOADING'
export const SET_GMAIL_LABELS = 'SET_GMAIL_LABELS'
export const SELECT_GMAIL_LABEL = 'SELECT_GMAIL_LABEL'
export const SET_GMAIL_EMAILS = 'SET_GMAIL_EMAILS'
let defaultState = {
profile: {
emailAddress: ''
},
loading: true,
labels: [],
currentLabel: null,
emails: []
}
export const connect = () => {
return (dispatch, getState) => {
dispatch(turnLoadingOn())
gmailAuth(false, populateCredentials(dispatch), clearCredentials(dispatch))
}
}...
I think you're right. The way I'm handling these situations is by loading the external JS file from React and using it in a promise.
So your flow should be something like this:
React app loads
React app injects your file in the HTML
Do your thing in step 2's callback or .then()
Create a helper function. Put it in a folder like helpers/load-script. Below you have all the code you should have in that file:
export default function loadScript(url, cb) {
var scr = document.createElement('script');
scr.type = 'text/javascript';
if (scr.readyState) { // IE
scr.onreadystatechange = function() {
if (scr.readyState ==`loaded' || scr.readyState ==='complete') {
scr.onreadystatechange = null;
cb();
}
};
} else { // Others
scr.onload = cb;
}
script.src = url;
document.getElementsByTagName('head')[0].appendChild(scr);
}
Next, import that function inside the component you want to use it into:
import React from 'react';
import loadScript from 'helpers/load-script';
class testComponent extends React.Component {
componentDidMount() {
loadScript('https://apis.google.com/js/client.js', () => {
// do mail api stuff here
});
}
render() {
return (
<div>hi there</div>
);
}
}
export default testComponent;
I had the same problem with GrowSurf Javascript Web API, The external script loaded after the render function, and its function was being undefined in componentDidMount().
This is a logic I used to get the GrowSurf function not to be undefined. It can also help anyone who wants to use a function of any external JS introduced in index.html.
You can use DOMSubtreeModified in componentDidMount() to check every time the DOM is modified, once the external JS is loaded(found) run your function there, and then stop the looping of DOMSubtreeModified.
componentDidMount() {
let functionDefined = false;
window.addEventListener('DOMSubtreeModified', function () {
if(!functionDefined) {
if (window.growsurf) {
console.log('a function is defined', window.growsurf.getReferrerId());
functionDefined = true;
}
}
}, false);
}
For your case, you can simply do this.
componentDidMount() {
let functionDefined = false;
window.addEventListener('DOMSubtreeModified', function () {
if(!functionDefined) {
if (window.gapi) {
// do mail api stuff here
functionDefined = true;
}
}
}, false);
}

Categories