Href Interpolation Failed in NextJs button - javascript

I have this code to create a button that makes the app change the language from English to Spanish (just add the 'es' after the root):
const { locale, locales, push, isReady } = useRouter()
const handleClick = l => () => {
push(`${currentPath}`, undefined, {locale:l})
this is the button code:
{locales.map(l => (
<button className="px-6 py-2 font-bold" key={l} onClick={handleClick(l)}>
{l}
</button>
))}
I click the language button in example.com/guides the app change the language to example.com/es/guides; but when I go to the dynamic path route example.com/guides/[url_en] and try to change the language, the following error it shows:
Unhandled Runtime Error
Error: The provided href (/guides/[url_en]) value is missing query values (url_en) to be interpolated properly. Read more: https://nextjs.org/docs/messages/href-interpolation-failed.

Related

Nuxt Error : Cannot read properties of null (reading 'addEventListener') default.vue and index.vue not rendering

I'm using nuxt.js and vuesax as an UI framework, I did modify my default.vue in /layouts with a basic navbar template exemple from vuesax.
Then I used #nuxtjs/router-extras to rename my "/" and redirect it to /login, I also used a vuesax input type template in my index.vue to see if I could render my /login page (navbar + input) but it is showing be this error:
client.js?06a0:103 TypeError: Cannot read properties of null (reading 'addEventListener')
at VueComponent.handleScroll (vuesax.js?574d:24324:1)
at VueComponent.mounted (vuesax.js?574d:24382:1)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1863:1)
at callHook (vue.runtime.esm.js?2b0e:4235:1)
at Object.insert (vue.runtime.esm.js?2b0e:3158:1)
at invokeInsertHook (vue.runtime.esm.js?2b0e:6390:1)
at Vue.patch [as __patch__] (vue.runtime.esm.js?2b0e:6609:1)
at Vue._update (vue.runtime.esm.js?2b0e:3960:1)
at Vue.updateComponent (vue.runtime.esm.js?2b0e:4075:1)
at Watcher.get (vue.runtime.esm.js?2b0e:4495:1)
again I'm very new, heres some code:
default.vue
<template>
<div class="center examplex">
<vs-navbar target-scroll="#padding-scroll-content" padding-scroll center-collapsed v-model="active">
<template #left>
<img src="" alt="">
</template>
<vs-navbar-item :active="active === 'wallet'" id="wallet">
Wallet
</vs-navbar-item>
<vs-navbar-item :active="active === 'profil'" id="profil">
Profil
</vs-navbar-item>
<template #right>
<vs-button>Login</vs-button>
</template>
</vs-navbar>
<Nuxt />
</div>
</template>
<script>
import Vue from 'vue'
import Vuesax from 'vuesax'
import 'vuesax/dist/vuesax.css' //Vuesax styles
Vue.use(Vuesax, {
// options here
})
export default {
name: 'DefaultLayout',
data:() => ({
active: 'wallet'
})
}
</script>
index.vue
<template>
<div class="center content-inputs">
hello
<vs-input
type="password"
v-model="value"
label-placeholder="Password"
:progress="getProgress"
:visiblePassword="hasVisiblePassword"
icon-after
click-icon="hasVisiblePassword = !hasVisiblePassword">
<template #icon>
<i v-if="!hasVisiblePassword" class='bx bx-show-alt'></i>
<i v-else class='bx bx-hide'></i>
</template>
<template v-if="getProgress >= 100" #message-success>
Secure password
</template>
</vs-input>
</div>
</template>
<router>
{
"path": "/login"
}
</router>
<script>
import Vue from 'vue'
import Vuesax from 'vuesax'
import 'vuesax/dist/vuesax.css' //Vuesax styles
Vue.use(Vuesax, {
// options here
})
export default {
data:() => ({
layout: 'default',
value: '',
hasVisiblePassword: false
}),
computed: {
getProgress() {
let progress = 0
// at least one number
if (/\d/.test(this.value)) {
progress += 20
}
// at least one capital letter
if (/(.*[A-Z].*)/.test(this.value)) {
progress += 20
}
// at menons a lowercase
if (/(.*[a-z].*)/.test(this.value)) {
progress += 20
}
// more than 5 digits
if (this.value.length >= 6) {
progress += 20
}
// at least one special character
if (/[^A-Za-z0-9]/.test(this.value)) {
progress += 20
}
return progress
}
}
}
</script>
middleware/redirect.js
export default function(req, res, next) {
const redirects = [
{
from: "/",
to: "/login"
}
]
const redirect = redirects.find((r) => r.from === req.url)
if (redirect) {
res.writeHead(301, { Location: redirect.to })
res.end()
} else {
next()
}
}
Vuesax is not really maintained anymore, latest commit being from 20th September 2020.
Hence why it's not part of the Nuxt CLI anymore.
If you're new, I recommend starting by using something more simple, well supported and maintained like Vuetify, Buefy, Tailwind or at least any other one available in the list.
Even starting directly with Nuxt without any prior Vue knowledge is quite risky.
Back to the topic, even if we fix the issues regarding a specific install issue here, we will probably face some others down the road. And since the project is not maintained anymore, it's pretty sure that at some point we will see a blocker of some sort.
Don't expect Vuesax to work with the new Nuxt3 at all for example. So yeah, sorry it's not an answer to your question but I feel like it's better if I tell you that now that later (after days of debugging).
PS: you're trying to use res.writeHead in a client-side middleware (redirect.js). If you want a redirect, you'll need to use more of a $router.push here to use the Vue router.

How to return a component/component-tag dynamically in vue/nuxt?

I am trying to convert a next.js app(https://medium.com/strapi/how-to-create-pages-on-the-fly-with-dynamic-zone-8eebe64a2e1) to a nuxt.js app. In this app I can fetch data from an API and the next.js app uses the APIs data to generate new pages with its corresponding content. Works well in Next.js.
The data/content from the API consists of Seo data for the page, some static values and very important of blocks. These blocks have an attribute called __component where the components name is saved and also have the components data like images, text, etc. So I only have to deal with next.js when adding new components.
In next.js I used the catch-all-route ./pages/[[...slug]].js to catch any slug an user may enter. Then the API is fired with the slug from the context.query and I get back the pages data if it exists. Now the APIs json data only needs to be passed to the blockmanager component.
const Universals = ({blocks}) => {
return <div><BlockManager blocks={blocks}></BlockManager></div>;
};
Here the blockmanager gets the json list of blocks, from which to parse the components.
import Hero from '../../blocks/Hero';
import Pricing from '../../blocks/Pricing';
const getBlockComponent = ({__component, ...rest}, index) => {
let Block;
switch (__component) {
case 'blocks.hero':
Block = Hero;
break;
case "blocks.prices":
Block = Pricing;
break;
}
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
};
const BlockManager = ({ blocks }) => {
return <div> {blocks.map(getBlockComponent)} </div>;
};
BlockManager.defaultProps = {
blocks: [],
};
export default BlockManager;
How can I replicate this line now in nuxt js?
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
How to return a component/component-tag dynamically in vue/nuxt ?
Is there maybe another solution to automatically insert the wanted component?
Maybe someones knows ho to convert the blockmanagers logic to vue/nuxt logic entirely.
I think you're looking for the is attribute. You can read about it here.
Your template would look like:
<component
:is="__component"
key={`index-${index}`}
/>
Ok I think I got it. No strange stuff actually. I thought about it too complicated. Wanted all dynamically created but no need as I saw later ...
<template v-if="blocks">
<div id="example-1">
<div v-for="({__component, ...rest}=block, i) in blocks" :key="i">
<Hero :data="rest" v-if="__component === 'blocks.hero'"/>
<Pricing :data="rest" v-if="__component === 'blocks.pricing'"/>
</div>
</div>
</template>
<script>
import Hero from '../../blocks/Hero/Hero.vue';
import Pricing from '../../blocks/Pricing/Pricing.vue';
export default {
components: {
Hero, Pricing
},
props: {
blocks: Array
}
}
</script>

Vanilla JavaScript to React Class/Component

I am new to react and this is my first site and I have some plan JavaScript I found online that will allow a word to be typed out and updated over a course of time. I have already made it into a react Component. But I am not sure how to covert this JavaScript Function into react code.
Here is my new React Component.
import React, {Component} from 'react';
class Hero extends Component {
render () {
return (
<div>
<section id="hero" className="d-flex flex-column justify-content-center align-items-center">
<div className="hero-container" data-aos="fade-in">
<h1>Augusto J. Rodriguez</h1>
<p>I'm a <span className="typed" data-typed-items="opption1, opption2, opption3, opption4"></span></p>
</div>
</section>
</div>
);
}
}
export default Hero;
Here is the vanilla JavaScript that I want to use in my code. Currently this is living in my main.js file that is being called from the index.html. this is the only part of the code that is not working.
if ($('.typed').length) {
var typed_strings = $('.typed').data('typed-items');
typed_strings = typed_strings.split(',')
new Typed('.typed', {
strings: typed_strings,
loop: true,
typeSpeed: 100,
backSpeed: 50,
backDelay: 2000
});
}
I am assuming I need to create a function where my tag is. But I am not sure how to do that in React.
any article references would be awesome or tips on how to resolve this. I have the full code for this project on GitHub.
Looks like that piece of code is using a library called Typed.js.
From looking at your project, I see you setup the Typed.js library inside your public/assets/vendor folder. Instead I would recommend using the NPM package manager to install and setup Typed.js, and copy over the code to work the React way. https://github.com/mattboldt/typed.js/.
Here's an example using Typed.js with React. https://jsfiddle.net/mattboldt/ovat9jmp/
class TypedReactDemo extends React.Component {
componentDidMount() {
// If you want to pass more options as props, simply add
// your desired props to this destructuring assignment.
const { strings } = this.props;
// You can pass other options here, such as typing speed, back speed, etc.
const options = {
strings: strings,
typeSpeed: 50,
backSpeed: 50
};
// this.el refers to the <span> in the render() method
this.typed = new Typed(this.el, options);
}
componentWillUnmount() {
// Make sure to destroy Typed instance on unmounting
// to prevent memory leaks
this.typed.destroy();
}
render() {
return (
<div className="wrap">
<h1>Typed.js</h1>
<div className="type-wrap">
<span
style={{ whiteSpace: 'pre' }}
ref={(el) => { this.el = el; }}
/>
</div>
<button onClick={() => this.typed.toggle()}>Toggle</button>
<button onClick={() => this.typed.start()}>Start</button>
<button onClick={() => this.typed.stop()}>Stop</button>
<button onClick={() => this.typed.reset()}>Reset</button>
<button onClick={() => this.typed.destroy()}>Destroy</button>
</div>
);
}
}
ReactDOM.render(
<TypedReactDemo
strings={[
'Some <i>strings</i> are slanted',
'Some <strong>strings</strong> are bold',
'HTML characters × ©'
]}
/>,
document.getElementById('react-root')
);
It looks like currently you're using the 'typed' library to create this typed list. There are some community packages that act as React wrappers for that, like this one:
https://www.npmjs.com/package/react-typed
Alternatively, you could do what that library does yourself, by loading the 'typed' package in a call to componentDidMount, passing in a React ref instead of a DOM element.
By the way, currently your code uses jQuery (assigned to the variable $) so it's not quite vanilla JS. You could replace the calls to $ with calls to document.querySelector, to make this vanilla JS (though your code might depend on jQuery elsewhere)

Switch the language in React without using external libraries

What ways to change language in React can you suggest without using external libraries? My way is to use the ternary operator {language === 'en'? 'title': 'titre'}. If language is en, displaytitle if not, display titre. What other way can you recommend. For example, that the translations should be placed in a separate json file.
Code here: https://stackblitz.com/edit/react-eu9myn
class App extends Component {
constructor() {
super();
this.state = {
language: 'en'
};
}
changeLanguage = () => {
this.setState({
language: 'fr'
})
}
render() {
const {language} = this.state;
return (
<div>
<p>
{language === 'en' ? 'title' : 'titre'}
</p>
<button onClick={this.changeLanguage}>change language</button>
</div>
);
}
}
Internationalization (i18n) is a hard problem with a few existing, standard solutions designed by expert translators and linguists to account for the breadth of language quirks across the world. You shouldn't generally try to come up with your own solution, even when you are fluent in all target languages.
That doesn't mean you need a library (you could implement one of those standards yourself) but writing the i18n logic inline will not scale and probably won't work well.
The easiest case of i18n is if you're translating strings that do not depend on context and are complete sentences with no interpolation. You could get away with a very basic approach there, like using a big dictionary of translations and just looking up each string in it. It would look sort of like your ternary but at least it would scale for many languages, and it would be reasonable to do that with no library:
l10n = {
'title': {en: 'title', fr: 'titre'}
}
<p>
{l10n['title'][lang]}
</p>
However, if there is going to be string interpolation in your website/application/whatever, please consider a library that implements, say, ICU.
Now, let me show you why it would be a bad idea. Suppose you have the string "you can see (n) rocks" where you want to replace (n) with an actual number, and you want the sentence to be grammatically correct so you need to compute number agreement, right ? so, "0 rocks", "1 rock", "2+ rocks"… looks like English plural is just adding an "s" (not true, but let's assume for now), you could implement that with ternaries. I see you used French in your example so, how about that ? "0 cailloux", "1 caillou", "2+ cailloux". Right, there are multiple plural forms in French. How do you write your code to account for that ? And what if you need a German translation ? maybe the translator will decide that the object should go first in the sentence, rather than last. How does your code handle word order based on language ?
All these problems should be delegated to the translator who encodes them into an ICU string, which is then evaluated by some code given a context to get a correct translation. Whether you use a library or implement it yourself, what you want in the end is some function — let's call it localize(string, context) that is pretty much independent from React and that you use in your components like this:
import localize from './somewhere'
<p>
{localize('title')}
</p>
If you really want to, you can pass the locale as an argument and have it stored in React's state somehow. This library decided it wasn't necessary because real users rarely switch language and it's OK to reload the whole application when that happens.
I just implemented a simple language component for work that uses a Localisation context/provider and a dictionary (e.g JSON). I'll go through the steps, and there's a workable codesandbox example at the end. This is a very basic approach, but it works well for us at the moment.
The example has:
1) A simple "dictionary" that contains the tokens you want to translate in each language defined by a short code
{ EN: { welcome: 'Welcome' }, FR: { welcome: 'Bienvenue' }, IT: { welcome: 'Benvenuto' } };
2) An initial state and reducer that you can update when the language changes
export const initialState = {
defaultLanguage: 'EN',
selectedLanguage: 'IT'
}
export function reducer(state, action) {
const { type, payload } = action;
switch (type) {
case 'LANGUAGE_UPDATE': {
return { ...state, selectedLanguage: payload };
}
default: return state;
}
}
3) A Localisation Context/Provider. You can wrap your code in the provider and every child component can get access to the state through the context. We import the dictionary and state/reducer, create the new context and then set up the provider into which we pass the state and dictionary.
import dictionary from './dictionary';
import { initialState, reducer } from './localisationReducer';
export const LocalisationContext = React.createContext();
export function LocalisationProvider({ children }) {
const localisationStore = useReducer(reducer, initialState);
return (
<LocalisationContext.Provider value={{ localisationStore, dictionary }}>
{children}
</LocalisationContext.Provider>
);
}
4) An example app. You can see the LocalisationProvider wrapping the other elements, but also a dropdown, and a component called Translate. I'll describe those next.
<LocalisationProvider>
<Dropdown />
<div className="App">
<h1>
<Translate token="welcome" />
</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</LocalisationProvider>
5) The dropdown accesses the Localisation context and builds a dropdown with the languages. The key part is the handleSelected function which uses the dispatch from the localisation store to change the state (update the language):
import { LocalisationContext } from './localisation';
const langs = [
{ shortCode: 'EN', label: 'English' },
{ shortCode: 'FR', label: 'Français' },
{ shortCode: 'IT', label: 'Italiano' }
];
export function Dropdown() {
const {
localisationStore: [ state, dispatch ]
} = useContext(LocalisationContext);
const { selectedLanguage } = state;
const handleSelected = (e) => {
const { target: { value } } = e;
dispatch({ type: 'LANGUAGE_UPDATE', payload: value });
}
function getOptions(langs, selectedLanguage) {
return langs.map(({ shortCode, label }) => {
return <option value={shortCode}>{label}</option>
});
}
return (
<select onChange={handleSelected}>
{getOptions(langs, selectedLanguage)}
</select>
);
}
6) The Translate component which also accesses the state and dictionary through the context, and performs the translation based on the selected language.
import { LocalisationContext } from './localisation';
export default function Translator({ token }) {
const {
localisationStore: [state], dictionary
} = useContext(LocalisationContext);
const {
selectedLanguage, defaultLanguage
} = state;
const translatedToken = dictionary[selectedLanguage][token] || dictionary[defaultLanguage][token];
return (
<Fragment>
{translatedToken}
</Fragment>
);
}
Here's the codesandbox example for you to explore. Just select a new language from the dropdown to see the main "welcome" text change.

Popper.js React Wrapper - React.createElement: type is invalid

I am trying to implement the standalone example from here, using react-popper - I basically just copy pasted the code for now. It does render the component. However, when I click everything breaks. I am using it in Gatsby.js - if that should make a difference?
That's the error(s) I'm getting:
index.js:2177 Warning: React.createElement: type is invalid --
expected a string (for built-in components) or a class/function (for
composite components) but got: undefined. You likely forgot to export
your component from the file it's defined in, or you might have mixed
up default and named imports.
Check your code at StandaloneExample.js:36.
And:
Uncaught TypeError: Object(...)(...) is not a function
at InnerPopper.render (Popper.js:159)
And:
The above error occurred in the component:
in InnerPopper (created by Context.Consumer)
in Popper (at StandaloneExample.js:34)
And multiple of these:
TypeError: Object(...)(...) is not a function
Here's my code:
import React, { PureComponent } from 'react'
import { Popper, Arrow } from 'react-popper'
import './popper.css'
class StandaloneExample extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
}
}
handleClick = (e) => {
console.log(e);
this.setState({
isOpen: !this.state.isOpen,
})
}
render() {
return (
<div>
<h2>Standalone Popper Example</h2>
<div
ref={div => (this.target = div)}
style={{ width: 120, height: 120, background: '#b4da55' }}
onClick={this.handleClick}
>
Click {this.state.isOpen ? 'to hide' : 'to show'} popper
</div>
{this.state.isOpen && (
<Popper className="popper" target={this.target}>
Popper Content for Standalone example
<Arrow className="popper__arrow" />
</Popper>
)}
</div>
)
}
}
export default StandaloneExample
I've modified things a bit (the way I implement state etc.), because I thought this might fix the errors I'm getting, but it didn't. Apart from that the code is pretty much the same as in the sandbox example - I'm not sure where it breaks.
edit: I am importing things like so:
import StandaloneExample from './MenuDropdown/StandaloneExample.js'
and am using it in my render function like so:
<StandaloneExample />
The example you linked is for react-popper#0.x.
Please check that you aren't with version 1 or greater.
react-popper V1 had breaking changes from V0.
You can find V1 doc here and V0 doc here.

Categories