What is the equivalent of Java singleton in React Native? - reactjs

Actually I am a Android Native Developer. I am new to React-Native. In Java i keep the users data and others data in Singleton Class and access from other activities. Then how i achieve this process in React native for access data's from other components or any alternative of singleton in React native.
I just try this but i received the error like getInstance() not defined.
class AppDelegate {
log = "This is AppDelegate";
static myInstance = null;
static getInstance() {
if (AppDelegate.myInstance == null) {
AppDelegate.myInstance = new AppDelegate();
}
return this.myInstance;
}
}
Thank you.

React is UI library, this isn't its responsibility. The question affects any JavaScript application, not only React.
JavaScript modules and ES modules in particular are evaluated only once under normal circumstances, this makes exports singletons:
// exported for extensibility
export class AppDelegate {...}
// a singleton
export default new AppDelegate;
Singleton class is potentially an antipattern in JavaScript. If there's a need for one object, it could be written as object literal.

Imports are cached, so if you export a class, the class will be cached, if you export an instance, the instance will be cached

If you need a singleton don't use a class at all.
Export the methods as a function instead.
// File app-delegate.js
let privateIstanceValue;
export const method1 = () => //do something;
export const method2 = () => //do something again;
Import using import * as
import * as appDelegate from './app-delegate.js';

Related

How to access a property of App() globally (in React App, from pyodide)

I have implemented pyodide in a React App like so.
In src/App.js in the example from the link above, let's say I have someProperty in App() that I want to access from script.py.
const App = () => {
const [output, setOutput] = useState("(loading...)");
const [someProperty, setSomeProperty] = useState("Initial state"); // this one
const runScript = code => {
window.pyodide.loadPackage([]).then(() => {
...
Under normal circumstances of pyodide, I would use import js to access javascript scope from python like in the docs.
The JavaScript scope can be accessed from Python using the js module (see Using Javascript objects from Python). This module represents the global object window that allows us to directly manipulate the DOM and access global variables and functions from Python.
However, the property is inside App(), not directly under window.
How would I access someProperty inside App() from script.py?
In other words, where is App() located under window property? Is it even possible to access properties of App() globally?
You should be able to create a JS object that has access to those local variables
let my_module = {
someProperty : function(){
return someProperty;
}
};
that you can then register as a Python module with,
pyodide.registerJsModule("my_js_module", my_module);
so it can then imported as,
from my_js_module import someProperty
See the documentation for more details. This will only work with the development version of pyodide or the upcoming 0.17.0 release.

React application with external plugins

I'm building a React application bundled using Parcel or Webpack.
The application should be able to embed external React components
developed by third-parties and hosted elsewhere as modern javascript modules:
// https://example.com/scripts/hello-plugin.js
import React from 'react';
export default class HelloPlugin extends React.Component {
render() {
return "Hello from external plugin!";
}
}
Host application loads these components using asynchronous import like this, for example:
// createAsyncComponent.tsx
import * as React from 'react';
import { asyncComponent } from 'react-async-component';
export default function createAsyncComponent(url: string) {
return asyncComponent({
resolve: () => import(url).then(component => component.default),
LoadingComponent: () => <div>Loading {url}....</div>,
ErrorComponent: ({ error }) => <div>Couldn't load {url}: {error.message}</div>,
})
}
But looks like bundlers don't allow importing arbitrary urls as external javascript modules.
Webpack emits build warnings: "the request of a dependency is an expression" and the import doesn't work. Parcel doesn't report any errors, but fails when import(url) occurs at runtime.
Webpack author recommends using scriptjs or little-loader for loading external scripts.
There is a working sample that loads an UMD component from arbitrary URL like this:
public componentDidMount() {
// expose dependencies as globals
window["React"] = React;
window["PropTypes"] = PropTypes;
// async load of remote UMD component
$script(this.props.url, () => {
const target = window[this.props.name];
if (target) {
this.setState({
Component: target,
error: null,
})
} else {
this.setState({
Component: null,
error: `Cannot load component at ${this.props.url}`,
})
}
});
}
Also, I saw a similar question answered a year ago where the suggested approach also involves passing variables via a window object.
But I'd like to avoid using globals given that most modern browsers support modules out of the box.
I'm wondering if it's possible. Perhaps, any way to instruct the bundler that my import(url) is not a request for the code-split chunk of a host application, but a request for loading an external Javascript module.
In the context of Webpack, you could do something like this:
import(/* webpackIgnore: true */'https://any.url/file.js')
.then((response) => {
response.main({ /* stuff from app plugins need... */ });
});
Then your plugin file would have something like...
const main = (args) => console.log('The plugin was started.');
export { main };
export default main;
Notice you can send stuff from your app's runtime to the plugin at the initialization (i.e. when invoking main at the plugin) of the plugins so you don't end up depending on global variables.
You get caching for free as Webpack remembers (caches) that the given URL has already loaded so subsequent calls to import that URL will resolve immediately.
Note: this seems to work in Chrome, Safari & firefox but not Edge. I never bothered testing in IE or other browsers.
I've tried doing this same sort of load with UMD format on the plugin side and that doesn't seem to work with the way Webpack loads stuff. In fact it's interesting that variables declared as globals, don't end up in the window object of your runtime. You'd have to explicitly do window.aGlobalValue = ... to get something on the global scope.
Obviously you could also use requirejs - or similar - in your app and then just have your plugins follow that API.
Listen to the Webpack author. You can't do (yet) what you're trying to do with Webpack.
You will have to follow his suggested route.

AngularJS 2: concurrent data access to proprety in an injectable class

The whole matter come up when we had a shared component #Injectable. Every component in the app.module.ts can inject it into his own constructor.
export class SimpleComponent {
constructor (private sharedComponent : SharedComponent){}
}
I write a method in this class SimpleComponent to set a proprety at the shared component:
setPropretyAtSharedComponent {
this.sharedComponent.setProprety("proprety")
}
Presuming that the SharedComponent held:
#Injectable()
export class SharedComponent {
proprety :any
constructor() {}
}
setProprety (proprety){
this.proprety = proprety;
}
At this point every thing is OK.
So I was wondering if I had two components at the same page which sets the proprety value of the SharedComponent at meanwhile (concurent access) how I can handle that?
I guess that's taken care of by the DI framework once you define your Injectable service in providers in your module. Once your service is defined in the module, you can inject it in different components as a singleton.
You can refer to these docs:https://angular.io/docs/ts/latest/guide/dependency-injection.html

Turning an ES5 React + Flux dispatcher test into ES6 fails

Their __tests__/TodoStore-test.js file:
https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/stores/tests/TodoStore-test.js
And their js/dispatcher/AppDispatcher.js file:
https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/AppDispatcher.js
In their case, the dispatcher is simply this:
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
And in their test's beforeEach it resets:
AppDispatcher = require('../../dispatcher/AppDispatcher');
Now, in my own project I'd like to use ES6's way of doing things. I'm not sure how, though. The differences between require and import elude me.
My dispatcher:
import { Dispatcher } from 'flux';
var dispatcher = new Dispatcher({
logLevel: 'ALL'
});
export default dispatcher;
Which–as a piece in the app–works fine in my app, but the require example above isn't having it.
The part of the test that needs to be converted to ES6's import:
beforeEach(function() {
AppDispatcher = require('./../src/dispatcher/dispatcher');
TodoStore = require('./../src/stores/TodoStore');
callback = AppDispatcher.register.mock.calls[0][0];
});
But, of course, this does not work:
beforeEach(function() {
AppDispatcher = import './../src/dispatcher/dispatcher';
// snip
});
Or:
import dispatcher from './../src/dispatcher/dispatcher';
beforeEach(function() {
AppDispatcher = new dispatcher();
// snip
});
I'm just doing by trial and error now and it's taking way too much time just to write a test.
My thought process:
They require whatever their dispatcher file outputs, which is always a new Dispatcher().
In my case, I'm creating a new Dispatcher and export that instance. Instead, I'd probably need to not instantiate it in the dispatcher file, but leave that up to the export, e.g.: export default new Dispatcher(), but that looks awful.
But no matter what I try I keep getting errors like:
TypeError: Cannot read property 'register' of undefined
Does anybody have a clue how to get this one up and running?
Much obliged!
The ES6 import Syntax is actually import defaultMember from 'module-name';
So in your case it would be
import AppDispatcher from './../src/dispatcher/dispatcher';
import TodoStore from './../src/stores/TodoStore';
For further info on ES6 import read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

Using Browserify to create React Bundle

It's the same question as here, but I don't understand the answer. So, my question is about the answer.
The answer is
Your react.js file/module isn't exposing the variables React and
ReactDOM you instantiate. In node, you make these methods public by
modifying the module.exports object like so:
module.exports = { React: React, ReactDOM: ReactDOM }
Finally, my question is: Where do "you make these methods public"?
You are making these methods public by defining them on the module.exports property. For instance, say you have a file reactExports.js with
var iWontGetThere = 'I am in this module only';
module.exports = { React: React, ReactDOM: ReactDOM }
now in another file, you can require these methods and use them, like so:
var React = require('reactExports').React;
var SweetComponent = React.createClass({
render: function() {
return (
<div>React is cool and I can use it in here!</div>
);
}
});
module.exports = SweetComponent;
Now imagine you want to render SweetComponent in another component. If I hadn't written module.exports = SweetComponent, requiring this module in another component would have no effect as all as you would be importing an empty object {}.
Let's say I tried to console.log(React.iWontGetThere); What would happen? I would get a reference error, as it was not exported with the contents of reactExports.js-it only exists in that module, but it is not exposed.
This is a contrived example, but the interesting story here is the ability to bring in encapsulated modules. I suggest reading more about node modules here
and checking out this answer as well.
and making some examples to get the hang of it.
tl;dr: defining variables and not having a module.exports = some_value statement then requiring that same file will default to an empty object.

Resources