I want to use events to communicate between native ios/android and my react native app.
I see two ways to do this: DeviceEventEmitter and NativeAppEventEmitter, which seem to be fairly identical.
What's the difference between them? Why should I pick one over the other?
Both DeviceEventEmitterand NativeAppEventEmitter are deprecated, you should use NativeEventEmitter instead.
I've found I need to use both when developing cross-platform native extensions that need to send events from Java/Obj-C to JavaScript.
On iOS you send events to JS like this:
[self.bridge.eventDispatcher sendAppEventWithName:#"myProgressEvent" body:#{
#"progress": #( (float)loaded / (float)total )
}];
.. which you pick up in JS using NativeAppEventEmitter.
In Java you send events to JS with:
WritableMap map = Arguments.createMap();
map.putDouble("progress", progress);
getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("myProgressEvent", map);
.. which you pick up in JS using DeviceEventEmitter
It's not ideal, as your JS code needs to then choose the right
emitter for the events to be received.
E.g.
const emitter = Platform.OS == 'ios' ? NativeAppEventEmitter : DeviceEventEmitter;
emitter.addListener("myProgressEvent", (e:Event)=>{
console.log("myProgressEvent " + JSON.stringify(e));
if (!e) {
return;
}
this.setState({progress: e.progress});
});
Related
I'm developing an app using CORDOVA and I am using localstorage in javascript
Can I use Cordova to access local storage in webview directly?
I looked at the documentation on the https://cordova.apache.org/docs/en/latest/ but couldn't find it.
Javascript code -
window.localStorage.setItem("test", "hello World");
ios native code -
I want
get("test");
yes it works on ios in javascript, to get the value :
window.localStorage.getItem("test");
more from cordova docs https://cordova.apache.org/docs/fr/latest/cordova/storage/localstorage/localstorage.html :
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
//
function onDeviceReady() {
window.localStorage.setItem("key", "value");
var keyname = window.localStorage.key(i);
// keyname is now equal to "key"
var value = window.localStorage.getItem("key");
// value is now equal to "value"
window.localStorage.removeItem("key");
window.localStorage.setItem("key2", "value2");
window.localStorage.clear();
// localStorage is now empty
}
to read :
https://github.com/react-native-community/react-native-webview/issues/73
How to set the local storage before a UIWebView loading its initial request?
I am caching a few images like:
Image.prefetch(`${remoteImageUrl}/100x100`)
Image.prefetch(`${remoteImageUrl}/800x800`)
Image.prefetch(`${remoteImageUrl}/1000x1000`)
While that is happening a component that wants to show the highest resolution version currently available may render.
if 1000 cached use 1000,
elseif 800 cached use 800,
elseif 100 cached use 100
How do I test "if 1000 is cached"?
I tried .complete this with no luck.
if (Image.prefetch(`${remoteImageUrl}/1000x1000`).complete) {}
How do you check the existence of a prefetched image in React Native?
It doesn't look like this is possible using the out of the box APIs.
First of all, Image.prefetch doesn't contain any other methods related to the prefetch cache.
Diving into the detail - on iOS, Image.prefetch calls the native RCTImageViewManager.prefetchImage method, which indirectly ends up loading the image and storing it in RCTImageCache. Since there are no bridged functions that access the image cache directly, you're somewhat out of luck.
However, you could work around it by wrapping your calls to Image.prefetch in a function that tracks which ones have completed:
// imagePrefetch.js
const prefetchedImages = {};
export function prefetchImage(url) {
return Image.prefetch(url)
.then(val => {
prefetchedImages[url] = true;
return val;
});
};
export function isPrefetched(url) {
return prefetchedImages[url] !== undefined;
}
Keep in mind that this is specifically a workaround for images you prefetch, not other images that happened to be cached from being loaded through other means.
I'm creating an ecommerce app that uses a geolocation library (https://github.com/transistorsoft/react-native-background-geolocation).
I have an orderState:
const ordersInitState = {
lineItems: [],
status: ORDER_STATUSES.AWAITING_CHECKOUT,
};
const ordersReducer = (prevState=ordersInitState, action) => {
switch(action.type) {
...
case actions.ORDERS.REMOVE_ITEM:
const lineItems = [...prevState.lineItems];
const indexToRemove = action.payload;
lineItems.splice(indexToRemove, 1);
const status = lineItems.length > 0 ? prevState.status : ORDER_STATUSES.AWAITING_CHECKOUT;
return {
...prevState,
status,
lineItems,
};
default:
return prevState;
}
}
export default ordersReducer;
As you can see, the client is allowed to remove items from their cart. If they end up removing everything, their order status will reset. If they do end up emptying their cart (lineItems.length === 0) I want to also run a simple line from the geolocation library:
BackgroundGeolocation.removeGeofence("blah");
Where would I put this? It feels wrong to do it in the reducer because it has nothing to do with state. It also isn't specific to one particular component, so putting it in one of my components doesn't make sense.
I'm still a bit new to redux so I'm not sure where to put non-state related methods.
The often used name for what you are looking for is called "side effects" middleware. In the abstract, you want to cause an effect in an external system (in this case, the geolocation library), when the application state changes.
There are many libraries for this use case. Some of the more popular ones are redux-saga and redux-loop. They are both good tools and help give structure to managing complicated side effects, but both come with a significant conceptual overhead, and should only be used when really needed.
If you want a quick and simple solution, you can create a plain JavaScript module that subscribes to your store changes and executes the side effects for you:
import store from '../your/redux/store;
let previousCount = 0;
store.subscribe(() => {
const count = store.getState().orders.lineItems.length;
if (count === 0 && previousCount > 0) {
// someone just emptied the cart, so execute side-effect
BackgroundGeolocation.removeGeofence("blah");
}
previousCount = count;
});
And then if you find yourself needing this type of solution repeatedly, you can reach for one of the libraries mentioned above.
I know this isn't google, but I wasn't able to find anything usefull and maybe you can give me some advice.
What I am looking for is some way to add an auto translation to strings in my react native application.
Right now I am using a workaround in which I translate some of the most common words manually - since that doesn't cover the whole language the outcome looks pretty unsatisfying :)
You could use react-native-i18n.
var I18n = require('react-native-i18n');
var Demo = React.createClass({
render: function() {
return (
<Text>{I18n.t('greeting')}</Text>
)
}
});
// Enable fallbacks if you want `en-US` and `en-GB` to fallback to `en`
I18n.fallbacks = true;
I18n.translations = {
en: {
greeting: 'Hi!'
},
fr: {
greeting: 'Bonjour!'
}
}
take user phone OS language using device info
https://www.npmjs.com/package/react-native-device-info#getdevicelocale
or using
I18n = require('react-native-i18n')
locale = I18n.currentLocale()
then Use power translator
https://www.npmjs.com/package/react-native-power-translator
//set your device language as a Target_Language on app start
TranslatorConfiguration.setConfig('Provider_Type', 'Your_API_Key','Target_Language', 'Source_Language');
//Fill with your own details
TranslatorConfiguration.setConfig(ProviderTypes.Google, 'xxxx','fr');
Use it as a component
<PowerTranslator text={'Engineering physics or engineering science refers to the study of the combined disciplines of physics'} />
add-on :
Use redux store or async storage to store all your string on first app start.
Then use translated text from store or storage.
IT will save your api bill as you have fixed strings.
sir for auto-translate. you can create one component where you can pass all strings (text) in your app, And use '#aws-sdk/client-translate' for translation, it's very fast and also works on dynamic data \
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-translate/index.html
https://www.npmjs.com/package/#aws-sdk/client-translate
I'm learning with Titanium to make iPhone/Android apps. I'm using Alloy MVC framework. I never used javascript before, apart from simple scripts in HTML to access the DOM or something like that, so I never needed to structure the code before.
Now, with Titanium, I must use a lot of JS code and I was looking for ways to structure my code. Basically I found 3 ways to do it: prototype, namespace and functions inside functions.
Simple example for each:
Prototype:
NavigationController = function() {
this.windowStack = [];
};
NavigationController.prototype.open = function(windowToOpen) {
//add the window to the stack of windows managed by the controller
this.windowStack.push(windowToOpen);
//grab a copy of the current nav controller for use in the callback
var that = this;
windowToOpen.addEventListener('close', function() {
if (that.windowStack.length > 1)
{
that.windowStack.pop();
}
});
if(Ti.Platform.osname === 'android') {
windowToOpen.open();
} else {
this.navGroup.open(windowToOpen);
}
};
NavigationController.prototype.back = function(w) {
//store a copy of all the current windows on the stack
if(Ti.Platform.osname === 'android') {
w.close();
} else {
this.navGroup.close(w);
}
};
module.exports = NavigationController;
Using it as:
var NavigationController = require('navigator');
var navController = new NavigationController();
Namespace (or I think is something like that, coz the use of me = {}):
exports.createNavigatorGroup = function() {
var me = {};
if (OS_IOS) {
var navGroup = Titanium.UI.iPhone.createNavigationGroup();
var winNav = Titanium.UI.createWindow();
winNav.add(navGroup);
me.open = function(win) {
if (!navGroup.window) {
// First time call, add the window to the navigator and open the navigator window
navGroup.window = win;
winNav.open();
} else {
// All other calls, open the window through the navigator
navGroup.open(win);
}
};
me.setRightButton = function(win, button) {
win.setRightNavButton(button);
};
me.close = function(win) {
if (navGroup.window) {
// Close the window on this nav
navGroup.close(win);
}
};
};
return me;
};
Using it as:
var ui = require('navigation');
var nav = ui.createNavigatorGroup();
Functions inside functions:
function foobar(){
this.foo = function(){
console.log('Hello foo');
}
this.bar = function(){
console.log('Hello bar');
}
}
// expose foobar to other modules
exports.foobar = foobar;
Using it as:
var foobar = require('foobar').foobar
var test = new foobar();
test.bar(); // 'Hello bar'
And now my question is: which is the better to maintain code clean and clear? It seems that prototype is clear an easy to read/mantain. Namespace confuses me a bit but only needs to execute the initial function to be "available" (no use of new while declaring it, I suppose because it returns the object?namespace? "me"). Finally, functions inside functions is similar to the last, so I don't know exactly the difference, but is useful to export only the main function and have all the inside functions available for use it later.
Maybe the last two possibilities are the same, and I'm messing concepts.
Remember that I'm searching for a good way to structure the code and have functions available to other modules and also inside the own module.
I appreciate any clarification.
In the examples that they release, Appcelerator appears to follow the non-prototype approach. You can see it in the examples they have released: https://github.com/appcelerator/Field-Service-App.
I've seen a lot of different approaches to structuring applications in Titanium before Alloy. Since Alloy, I've found following the development team's examples helpful to me.
With that being said, it seems to me that all of this is still under interpretation and open to change and community development. Before Alloy there were some great community suggestions on structuring an app and I believe that it is still open with Alloy. Often when I find someone's example code I see something they did with it that appears to organize it a bit better than I thought of. It seems to make it a bit easier.
I think you should structure your application in a way that makes sense to you. You may stumble on to a better and easier way of developing applications with Alloy, because you are looking at it critically.
I haven't found a lot of extensive Alloy examples, but Field-Service-App makes sense to me. They have a nice separation of the elements in the application beyond MVC. Check it out.