I want to write a plugin that contain all needed services and use this services easily when is needed.
I have wrote a plugin but it doesn't work !!
How to know what is wrong ?
This is plugin i wrote .
export default ({ $axios}:any , inject:any) => {
class BlogService {
getPost() {
return $axios.$get('/posts')
}
delete(id: Number) {
return $axios.Sdelete('/post/' + id)
}
}
inject(new BlogService)
}
And this is error i get
The inject method takes in two parameters. The first parameter is a string and will be the name of the property and then the second argument is the value (in your case, new BlogService()). I would also add the value to the context, so that you can access your service in asyncData and anywhere else the context is available.
Here's a rewritten version of your snippet, with these changes applied:
export default (context, inject) => {
const { $axios } = context
class BlogService {
getPost() {
return $axios.$get('/posts')
}
delete(id) {
return $axios.Sdelete('/post/' + id)
}
}
const blogService = new BlogService()
context.$blogService = blogService // Adds $blogService to the context.
inject('blogService', blogService) // Adds $blogService to all of your components.
}
While you haven't tagged your post with TypeScript, it looks as if you're using TypeScript in your original snippet, so I've also rewritten the snippet for TypeScript as you'll need to extend the default types with your new injected property. This is just to stop your linter from going crazy and your code completion to work.
import { Context, Plugin } from '#nuxt/types'
class BlogService {
readonly context: Context
constructor (context: Context) {
this.context = context
}
getPost() {
return this.context.$axios.$get('/posts')
}
delete(id: number) {
return this.context.$axios.Sdelete('/post/' + id)
}
}
// Create a new interface so that you don't have to add the new properties to all of the existing types every time.
interface Services {
$blogService: BlogService
}
declare module 'vue/types/vue' {
interface Vue extends Services {
}
}
declare module '#nuxt/types' {
interface NuxtAppOptions extends Services {
}
interface Context extends Services {
}
}
const servicesPlugin: Plugin = (context, inject) => {
const { $axios } = context
const blogService = new BlogService(context)
context.$blogService = blogService // Adds $blogService to the context.
inject('blogService', blogService) // Adds $blogService to all of your components.
}
export default servicesPlugin
i used above code and there is some error here .#tarkan
Related
I have two MobX stores:
export default class AccountStore {
accounts : Account[] = [];
constructor() {
makeAutoObservable(this);
}
loadAccounts = async () => {
//call to loadOthers
}
}
and
export default class OtherStore {
others : Others[] = [];
constructor() {
makeAutoObservable(this);
}
loadOthers = async () => {...}
}
In my AccountStore class, in my loadAccounts function I want to make a call to loadOthers from the other MobX store. How can I make this call?
Depends on how you initialize your stores. The most simple way is to have singleton stores, that way you can just import it directly.
Another way is you have some sort of root store, which initializes all other store, and pass itself to every store too, that way you have reference to the root store and to every other store from any store. Something like that:
class RootStore {
constructor() {
this.accountStore = new AccountStore(this)
this.otherStore = new OtherStore(this)
}
}
class AccountStore() {
constructor(rootStore) {
this.rootStore = rootStore.
}
loadAccounts = async () => {
this.rootStore.otherStore.callOthers()
}
}
Third way is just pass OtherStore instance to loadAccounts function. For example if you want to call loadAccounts when some React component mounts you can do that in useEffect, just get both store, and pass one to another:
export default class AccountStore {
// ...
loadAccounts = async (otherStore) => {
// ...
otherStore.loadOthers()
}
}
How can we use a mobx store in utility function?
I have a mobx store and a utility function to make a axio call, I want to use stote value in the utility, how can I do this?
// Store example
export default class SampleStore {
#observable title = "Coding is Love";
#observable user = {
userId: 1,
};
#action
setUser(user) {
this.user = user;
}
#action
updateUser(data) {
this.user = { ...this.user, ...data };
}
#action
clearUser() {
this.user = undefined;
}
#action
setTitle(title) {
this.title = title;
}
}
// Utility function in different file
export function makeApiCall () {
// Use SampleStore here
}
Depends on how you actually initialize your store, how your app is organized and many other factors.
Most simple way is to have singleton store and then you just import it and use directly:
// export an instance instead
export const sampleStore = new SampleStore()
// .. util fil
import { sampleStore } from './SampleStore.js'
export function makeApiCall () {
sampleStore.setUser()
}
Another way is just to pass store to the function, for example if you want to make this call inside useEffect or something:
// Make function accept store as an argument
export function makeApiCall (sampleStore) {
sampleStore.setUser()
}
// ... inside of some React component
// get store from the context (I guess you will have it at that point)
const { sampleStore } = useStores()
useEffect(() => {
// and just pass to the function
makeApiCall(sampleStore)
}, [])
I have a set of functions in a util module. Most of the functions are simple data manipulation, however, one of them makes a REST call. Many modules/classes call this method that makes the REST call for its values. Instead of the app/browser making multiple (>20) of the calls, can i make 1, and save the result. Then return the saved result and refrain from making subsequent calls?
utils.ts
import axios from 'axios'
import { of, from } from 'rxjs';
import { shareReplay, switchMap, first } from 'rxjs/operators';
let cache: Observable<any>; // <-- global cache to set/get
export function makeRequest() {
const promise = axios.get('http:rest-server:1234/user/data');
const obs = from(promise);
return obs.pipe(
map(res => { return of(res) })
catchError(err => { cache })
);
}
export function getUserData() {
if(!cache) { // <-- if cache isnt empty, make the REST call
cache = makeRequest()
.pipe(
shareReplay(2),
first()
)
}
return cache; // <- return the originally populated cache
}
index.ts
import * as Config from './utils';
myComponent.ts
import { Config } from 'my-helper-library';
export class MyComponent {
public init() {
Config.getUserData()
.subscribe(.......
}
}
Note, this singleton will be consumed by both Angular and React apps.
I implemented a native module which navigates to a camera activity. But while calling the camera from nativeModules, it takes 1500-2000ms to open(excluding ui updation in camera).
The native module class that extends ReactContextBaseJavaModule is written like this:
#ReactModule(name = ImagePickerModule.NAME)
public class ImagePickerModule extends ReactContextBaseJavaModule
implements ActivityEventListener
{
....
// Calling this method
#ReactMethod
public void launchCamera(final ReadableMap options, final Callback callback) {
// this method opens camera after checking necessary permissions and applies UI changes which was set by the user previously
}
....
}
And this is nativeModules to JS mapping in the .ts file
import {NativeModules} from 'react-native';
import {ImagePickerNativeModule} from './privateTypes';
const NativeInterface: ImagePickerNativeModule | undefined =
NativeModules.ImagePickerManager;
const DEFAULT_OPTIONS: ImagePickerOptions = {
// options here
}
class ImagePicker {
launchCamera(options: ImagePickerOptions, callback: Callback): void {
return NativeInterface.launchCamera(
{
...DEFAULT_OPTIONS,
...options,
tintColor: processColor(options.tintColor || DEFAULT_OPTIONS.tintColor),
},
callback,
);
}
}
I am calling the nativeModule from react-native code like this:
export const CustomCamera = (): Promise<{ uri: string }> => {
return new Promise((resolve, reject) => {
ImagePicker.launchCamera(***Camera options passed***)
.then(res => // Do something here)
.catch(err => // Do something here)
}
}
Is there any way I can open the activity faster while calling it from native modules? or keep the activity in the background so that the cameraActivity can load fast while calling it from react-native? Please suggest.
in my react native app I want to use mobx for state management, my store is divided in multiple stores/files and since I want to be able to call a store actions from another stores I'm implementing a GlobalStore where I instantiate the other stores.
I want to be able to do something like this from my components
import { PostStore } from '../stores/PostStore.js'
import { UserStore } from '../stores/UserStore.js'
import { VenueStore } from '../stores/VenueStore.js'
class GlobalStore
{
postStore = new PostStore(this);
userStore = new UserStore(this);
venueStore = new VenueStore(this);
}
export default new GlobalStore;
This makes it so that using react-native Context-Provider API I can call every store action in ALL my compoennts using globalStore as a link:
In any component I can do:
globalStore.postStore.listPosts()
However I'm still not sure how I can access other store actions from within OTHER STORES.
What if inside postStore I want to use spinnerStore (to show axios calls pending, error or success status):
#action.bound getPosts = flow(function * (payload)
{
this.spinnerStore.setData({status: 1});
try
{
this.spinnerStore.setData({status: 2, response: response});
let response = yield axios.get('/api/posts', { params: payload })
return response;
}
catch (error) {
console.error(error);
this.spinnerStore.setData({ status: 3, errors: error });
throw error;
}
})
Here spinnerStore would be undefined...
However I'm still not sure how I can access other store actions from within OTHER STORES.
When you instantiate a store you can assign one of its properties to be another store instance. This is what you included in your example
class Foo {
constructor(instance) {
this.instance = instance
}
}
class Bar {}
const foo = new Foo(new Bar());
foo.instance instanceof Bar; // true
Now your foo instance has access to any public properties/methods defined on Bar
class Foo {
constructor(instance) {
this.instance = instance
}
}
class Bar {
#observable isLoading = false;
#observable data = null;
#action
getData() {
this.isLoading = true;
return axios.get('/foo').then((data) => {
this.isLoading = false;
this.data = data;
}).catch(e => {
this.isLoading = false;
});
}
}
const foo = new Foo(new Bar());
// in react
const MyComponent = ({ foo }) => (
<div>
{foo.instance.isLoading && <Spinner />}
<button onClick={foo.instance.getData}>
will call Bar action from Foo store
</button>
</div>
);
export default lodash.flowRight(
mobx.inject((stores) => ({ foo: stores.fooStore })),
mobx.observer
)(MyComponent)
In your example with generators, you cannot use fat arrows so this isn't bound to your class instance anymore, which is why it will be undefined. Using promises and fat arrows solves that problem.