Gatsby & React Context API: Using Context to set languages for internationalization - javascript

Currently working on a Gatsby project and attempting to implement i18n/internationalization. I want to serve English and French versions of my site.
I'm following along with this tutorial to implement this. I'm running into a problem when it comes to using the Context API to create context and pass it to my components. In the tutorial I'm following there is an odd syntax that I'm unsure of:
const PageContext = React.createContext<PageContextValue>({})
Here is the full component in which the context is created using createContext:
import React from 'react'
import { useTranslation } from 'react-i18next'
const PageContext = React.createContext<PageContextValue>({})
export const PageContextProvider = ({ pageContext, children }) => {
const { i18n } = useTranslation()
i18n.changeLanguage(pageContext.lang)
return <PageContext.Provider pageContext={pageContext}>{children}</PageContext.Provider>;
}
export const usePageContext = () => React.useContext(PageContext)
It produces the following error:
What is causing this error? I don't know much about the Context API but the React.createContext<PageContextValue>({}) syntax looks strange and throws an error.

The createContext is a generic method, so the PageContextValue is the type of your context's value.
The tutorial doesn't seem to define this value (which is an issue in my opinion), but you could do so by:
type PageContextValue = {
// Your type definition here
}
However, typescript is smart enough to infer the type itself, so you can just create the context:
const PageContext = React.createContext({})
Note that the type is static once it's defined, so if you actually pass a {} that'll be the set type and you wont be able to actually add values to your context, otherwise you'll receive typescript errors. So make sure to:
Either define the type as shown above
Or add default values when creating the context to make sure typescript infers it correctly, for example: const PageContext = React.createContext({counter: 0}) would allow you to access counter on your context later without an error.
Edit: Just figured out you are not using typescript. The tutorial you've posted is written in typescript! You'll stumble upon more errors if you continue using its syntax so I suggest you just use typescript for your project. But just for this error, it can be fixed removing the generic type (<PageContextValue>)

Related

How to describe type for a generic component export in flowjs

I'm upgrading code to types-first and stuck upon need to explicitly declare type of generic react component via flowjs annotations
// #flow
import * as React from 'react';
type P<TArg> = {
items: TArg[],
onSelect: (props: TArg) => void
}
type Item = {
key: string
}
class Autocomplete<TElem: Item> extends React.Component<P<TElem>> {
}
//its external function provided via import, i put it here for simplicity
function woodoo<F>(v: F): F {
return v
}
If i try to export result of calling the function:
export default woodoo(Autocomplete)
I will get following error:
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression.Flow(signature-verification-failure)
If I try to export it via component:
export default (woodoo(Autocomplete): Autocomplete)
I will get following error:
Cannot use Autocomplete [1] without 1 type argument.Flow(missing-type-arg)
I know export should be more like
export default (woodoo(Autocomplete): React$ComponentType<????>)
but idk what to put in angle backets to achieve proper typing.
Making the component covariant instead of generic is not valid since the expected value passed in onSelect function is exactly the same that provided via items property and usage of covariance would not yield the same level of strictness as usage of generic would.
Have you tried this?
export default (woodoo(Autocomplete): typeof Autocomplete);
I got this answer straight up from using vscode using the quick fix feature
The easiest approach is to hover the component, check it type, and fill at the export.
Anyway you can try:
export default (woodoo(Autocomplete): React.Element<typeof Autocomplete>)

create my own global variable in nuxt.js (with vuetify)

I'm developing an app with nuxt and I'm tired of having to write an if statement in pages using this.$Vuetify.breakpoint.name == 'xs' for responsiveness every time. So I would like to create my own variable and call this long variable.here is my code↓
(mynuxtapp/plugins/createCustomVar.js)
import Vue from "vue";
Vue.prototype.$bp = Vue.prototype.$vuetify.breakpoint.name;
console.log(Vue.prototype.$bp);
I have already set nuxtconfig to run the plugin.
But it returns an error:
TypeError: Cannot read property'breakpoint' of undefined.
Apparently I can't access vuetify using "$", even though I can do it in pages.
What should I do? and Are there any easier ways or best practices?
Thank you for reading the question at the end!
The $vuetify property exists on the Nuxt context, not the Vue prototype.
Each module under plugins/ should return a function that receives the Nuxt context as the first argument. That context contains the $vuetify object setup by the #nuxtjs/vuetify plugin.
The second argument of the Plugin API is inject, which allows you to inject globals into the Nuxt context.
So your plugin should look similar to this:
// ~/plugins/myGlobals.js
export default ({ $vuetify }, inject) => {
// inject makes `$bp` available in context (the `$` prefix is automatically prefixed)
inject('bp', $vuetify.breakpoint.name)
}
demo
How about to start with you simply log out the context object and see what you have. I think you'll probably find that the Vuetify object is lying somewhere else.
export default (context, inject) => {
console.log('context:', context)
}
Docs for setting plugins can be found here

Is there a way to add Types Definition/Declaration for bind functions?

I'm learning TypeScript now and I have been wanting to create and contribute my own Type Def File.
So I was having trouble lately to get the Intellisense to work with the type because of this binding function
declare module 'jshue' {
export interface IHue {
discover: () => Promise<Array<any>>,
bridge: (ip: string) => any
}
var jsHue:IHue = jsHueAPI.bind(null, fetch, Response, JSON, Promise);
export default jsHue;
}
The problem with this is that when I import the library and try to use it, an error message will be prompted saying that
This expression is not callable.
Type 'IHue' has no call signatures.
It will work if I declare a type when declaring jsHue, It's just that it will defeat the purpose of having type definition file.
import jsHue, { IHue } from 'jshue';
const hue:IHue = jsHue();
Also, is there a way that I could avoid declaring a new variable with jsHue()?
Is there any other solution for this to work?
JS Library for jsHue
Resolved with the help from Bergi
Solution here https://github.com/blargoner/jshue/pull/23

Polkadot-js Babel error when add custom #polkadot/types

I'm setting up a Nuxt.js app with #polkadot-js. When I do request to custom substrate runtime module with my #polkadot/types - I'm getting this error Class constructor Struct cannot be invoked without 'new'.
This is for a Nuxt.js app with official setup of typescript. In the past, I've tried to setup it with clean Nuxt.js and Vue but always the same error. Only if I setup clean NodeJS (with or without typescript) or with #polkadot react apps - it works well.
I've created a repository to try some other ways.
API call:
class VecU32 extends Vector.with(u32) {}
class Kind extends Struct {
constructor(value) {
super({
stuff: VecU32
}, value);
}
}
const Alice = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const provider = new WsProvider("ws://127.0.0.1:9944");
const typeRegistry = getTypeRegistry();
typeRegistry.register({ Kind });
const api = await ApiPromise.create(provider);
// With types providede in create function - works well
// types: {
// Kind: {
// stuff: "Vec<u32>"
// }
// }
const res = await api.query.template.kinds(Alice);
console.log(res);
I expect empty (or some values, depending on what is in the blockchain) result output, but the actual output is the error, Class constructor Struct cannot be invoked without 'new'.
Short answer:
Instead of this const typeRegistry = getTypeRegistry();, do:
const typeRegistry.register({
Kind: {
'stuff': 'Vec<u32>'
}
});
Longer answer
When you're calling typeRegistry.register({ Kind }); you're trying to register the Typescript class as a custom type in the registry, but the types you need to pass to the type registry of the API have nothing to do with your Typescript types, these two are not directly associated to each other.
Event if you'd be writing plain Javascript you would need to register your custom Substrate Types in the Polkadot-JS API.
The types passed to the API are used to decode and encode the data you're sending and receiving to/from your substrate node. They are compliant with the SCALE codec which is also implemented in the Substrate core Rust code. Using these types makes sure that the data can be correctly de- and encoded in different environments and by different languages.
You can read more about it here: https://substrate.dev/docs/en/overview/low-level-data-format
The Javascript representation of these types are what's listed as "Codec types" in the Polkadot-JS docs:
https://polkadot.js.org/api/types/#codec-types
All the other types you find in the Polkadot-JS docs are extensions of these low-level codec types.
What you need to pass to the JS-API are all custom types of all your custom substrate modules so that the API knows how to de- and encode your data, so in your case what you declared here in Rust:
pub struct Kind {
stuff: Vec<u32>,
}
needs to be registered like this in Javascript:
const typeRegistry.register({
Kind: {
'stuff': 'Vec<u32>'
}
});
Your Typescript types on the other hand are there to make sure that the data your handling client side in your frontend written in typescript has the correct types.
They're only needed by Typescript and they're adding an extra layer of security, but the types itself are not needed to communicate with the API. Your data definitely needs to have the correct format to prevent errors, though.
You can think of https://www.npmjs.com/package/#polkadot/types as a Substrate/ Polkadot specific version of https://github.com/DefinitelyTyped/DefinitelyTyped
But even if you're not using Typescript https://polkadot.js.org/api/types/ is still 100% your go-to reference.

BehaviorSubject gives error for next function when i try to add the variable using next()." I get the error this.count.next is not a function"

Inside Angular service i have a variable count, which i want to observe whenever it's updated, i want to set that updated value to another variable in a different component.
import {BehaviorSubject} from "rxjs/BehaviorSubject";
import 'rxjs/Rx';
export class DashboardService{
count = new BehaviorSubject<number>(0);
count$=this.count.asObservable();
addCount(data){
this.count.next(data);
}
}
I get the error eventhough i have imported all the relevant libraries .Any idea why i'm getting this? can anyone tell me what's happening with the code ?
}
rxJs version 5.4.3 latest!
Try this:
export class DashboardService {
count = new BehaviorSubject<number>(0);
count$ = this.count.asObservable();
public addCount = (data) => {
this.count.next(data);
}
}
The issue you are encountering is that you are using addCount in a context where this inside the function is altered (i.e. pointing to something else). Using lamda based functions in typescript ensures this can not happen. This is not an excuse for always using them however.
I recommend you read up a bit on lambda/arrow functions, it might also be a good idea to look in to how this works in javascript and in typescript.

Categories

Resources