Dynamically use [lng].js in React component - javascript

I'm creating a node module for React just to try myself out and learn more. But I'm facing a problem. I want to make this module without any dependencies (except React) but I also want to have I18n in my module. I have started out like with this file structure:
src
|- Components
| |- myComponent.jsx
|
|- I18n
| |- en-us.js
| |- sv-se.js
|
|- index.jsx
So I want to use the I18n js files depending on which language the user calls to the module. Here are my current files:
index.jsx:
import React from 'react';
import Component from './Components/component';
class MyNewModule extends React.Component {
constructor(props) {
super(props);
this.state = {
greetings: [],
};
}
componentDidMount() {
this.setState({ greetings: [
'Hola',
'Como estas?',
'Como te llamas?',
] }); // Will use props later so user can send to module
}
render() {
return (
<Component greetings={this.state.greetings} locale={this.props.locale} />
);
}
}
export default MyNewModule;
myComponent.jsx:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
greetings: [],
};
this.getGreetings = this.getGreetings.bind(this);
}
componentDidMount() {
this.getGreetings();
}
getGreetings() {
let greetings;
if (props.greetings && props.greetings.length) {
greetings = props.greetings;
} else {
greetings = []; // HERE I WANT TO FETCH GREETINGS FROM FILE BY props.locale
}
this.setState({ greetings });
}
render() {
return (
<div>
{this.state.greetings.map((g, i) => {
return (
<div key={i}>
{g}
</div>
);
})}
</div>
);
}
}
export default MyComponent;
en-us.js:
function Lang() {
return {
greetings: [
'Hello',
'How are you?',
'What is your name?',
],
};
}
export default Lang;
sv-se.js
function Lang() {
return {
greetings: [
'Hej',
'Hur mår du?',
'Vad heter du?',
],
};
}
export default Lang;
As you can see I want to basically fetch the greetings from the corrent language file, depending on which locale the user use as property.
I have tried finding a good way to do this, and the only way I have found is to use require as stated in Dynamically import language json file for react / react-intl but I feel that there might be a better and more "reacty" way to do this.
Any suggestions?
EDIT 1:
After suggestion from #Ozan Manav I changed the language files to use
function Lang() {
greetings: [
'Hello',
'How are you?',
'What is your name?',
],
}
and call it by using:
greetings = require(`./I18n/${this.props.locale}.js`).Lang.greetings;
but I would still like to not have to use require if possible.

Why are you trying to return it as a function?
Maybe you can use as Greetings ["en-EN"] or Greetings ["sv-SE"]
export const Greetings = {
"en-EN": ["Hello", "How are you?", "What is your name?"],
"sv-SE": ["Hej", "Hur mår du?", "Vad heter du?"],
};
Could that be?

Related

Babel React transpiling to `fileName.Component` instead of just `Component`

I am having to call my react component as component.Component, like below. Also to note, the first part is the file name. If the rename the file, I have to say (newFileName.LikeButton).
instead of
ReactDOM.render(React.createElement(LikeButton) , domContainer);
Any idea how I can resolve this? Here is my setup. My babel.config.json
{
"presets": ["#babel/preset-react", "#babel/preset-env" ],
"plugins": [ "#babel/plugin-transform-modules-umd" ]
}
my react component in likeButton.jsx
export class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
render() {
if (this.state.liked) {
return 'You liked this.';
}
return (<button onClick={() => this.setState({ liked: true }) }>
Like
</button>
);
}
}
Warning, this answer is speculative (but too long for a comment)
I suspect your imports look something like this:
import likeButton from './somePath/likeButton'
but, because you are using named exports, (as opposed to default exports), your import should actually look like:
import { LikeButton } from './somePath/likeButton'
to "destructure" LikeButton from the module.

React Context error on rendering

I created an app to learn ReactJS. Unfortunately, when I was trying to use context I got 1 error on rendering, but my app compiles well.
This is my code:
import React, {Component} from 'react';
const LoginContext = React.createContext(null);
const user = {
isLoggedIn: true,
username: 'test',
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
user: user,
};
}
render() {
return (
<LoginContext.Provider user={this.state.user}>
<Welcome/>
</LoginContext.Provider>
);
}
}
class Welcome extends Component {
render() {
return (
<div>
<WelcomeText/>
</div>
);
}
}
class WelcomeText extends Component {
render() {
return (
<LoginContext.Consumer>
<div>
{(user) => (<p>{user.username}</p>)}
</div>
</LoginContext.Consumer>
);
}
}
export default App;
This is the error:
updateContextConsumer
http://localhost:3000/static/js/bundle.js:20927:23
20924 | {
20925 | ReactCurrentOwner.current = workInProgress;
20926 | ReactDebugCurrentFiber.setCurrentPhase('render');
> 20927 | newChildren = render(newValue);
| ^ 20928 | ReactDebugCurrentFiber.setCurrentPhase(null);
20929 | } // React DevTools reads this flag.
20930 |
Can you help me solve this?
ContextProvider needs a prop called value and not user
<LoginContext.Provider value={this.state.user}>
<Welcome/>
</LoginContext.Provider>
Also the Context consumer has the children as a function and not the div
class WelcomeText extends Component {
render() {
return (
<LoginContext.Consumer>
{(user) => (<div><p>{user.username}</p></div>)}
</LoginContext.Consumer>
);
}
}
I am currently working on React-16.8.6 and having an interesting bug.
I'm not sure if it's the known issue or not but I am having the same error whenever I have a space between two characters '}' and '<' as you can see it line-30.
After (1) removing the space or (2) completely making a new line with , it was resolved.
Even though I love React a lot, it's not perfect and we can make it better together.

How to retrieve ref from hoc translated component by i18next

I use i18next to translate my components in separate repo. Now I need to use method from one component in my main project.
This is example component:
class ExampleComponent extends React.Component {
constructor(props) {
this.state = {
text: '',
};
this.resetText = this.resetText.bind(this);
}
resetText() {
this.setState({
text: '',
});
}
render() {
<div/>
}
export default translate('components', { withRef: true })(ExampleComponent);
And now I need to use resetText in my main project, without translations it works fine
class MainComponent extends Component {
resetComponent() {
return () => this.exampleComponent.resetText();
}
renderExampleComponent() {
return (
<ExampleComponent
ref={(exampleComponent) => { this.exampleComponent = exampleComponent; }}
/>
);
}
render() {
return (
<div>
{this.resetComponent()}
</div>
);
}
I tried this.refs.exampleComponent.resetText(); but it not works.
In i18next documentation I found "withRef | store a ref to the wrapped component and access it by decoratedComponent.getWrappedInstance();" but where should I use this getWrappedInstance() to make it works?
Someone have experience with this?
Greetings
I think with the provided code, your ref returns a wrapper, so you need to call getWrappedInstance on it: this.refs.exampleComponent.getWrappedInstance().resetText();

How to define state in react components?

I am quite new to React and wonder how this should work:
class App extends Component {
> 4 | state = {
| ^
5 | bands: [],
6 | concerts: []
7 | }
here the error message:
ERROR in ./src/App.js
Module build failed: SyntaxError: Unexpected token (4:8)
Edit (the whole component):
import React, { Component } from 'react'
class App extends Component {
state = {
bands: [],
concerts: []
}
render() {
return <div>hei</div>
}
}
export default App
Some solution to this?
If the code is really as shown, you're trying to use a language feature ("class fields") that isn't in the language yet, it's still a stage 3 proposal. You need to ensure whatever transpiler you're using handles transpiling that.
If you don't want to use class fields, define your state property in a constructor:
class App extends Component {
constructor(...args) {
super(...args);
this.state = {
bands: [],
concerts: []
};
}
render() {
return <div>hei</div>
}
}
One option would be to put the state inside your constructor:
class App extends Component {
constructor(props) {
super(props)
this.state = {
bands: [],
concerts: []
};
}
render() {
// Here you can access to this.state
return <div>hei</div>
}
}

Writing Components in React - MERN stack issues

I am trying to figure out how to write a Component in a MERN app.
This is my best effort, taking account of this advice on how to go about it?
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactBootstrap from 'react-bootstrap'
var GreeterMessage = require('GreeterMessage');
var GreeterForm = require('GreeterForm');
class Greeter extends React.Component {
getDefaultProps: function () {
return {
name: 'React',
message: 'This is the default message!'
};
},
getInitialState: function () {
return {
name: this.props.name,
message: this.props.message
};
},
handleNewData: function (updates) {
this.setState(updates);
},
render: function () {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
When I save this and run web pack in my terminal to check everything, I get this feedback:
ERROR in ./app/components/Greeter.jsx
Module build failed: SyntaxError: Unexpected token (9:19)
7 |
8 | class Greeter extends React.Component {
> 9 | getDefaultProps: function() {
| ^
10 | return {
11 | name: 'React',
12 | message: 'This is the default message!'
# ./app/app.jsx 19:14-32
I can't find any resources to help me figure out what a token is, let alone when they are expected or unexpected.
Can anyone see where I'm getting this wrong? I've just finished 5 separate udemy courses that are supposed to be an intro to react and MERN, and I can't get the first step to work.
It looks like your mixing the older React.createClass syntax with the latest ES6 class notation. You can't mix and match :)
You're also using both CommonJS and ES6 versions of importing code into your file. Although this won't break the code (unless you're using a setup that doesn't support import, I would advise dine consistently wouldn't go amiss.
Here is an example of an amended version of your code to use the ES6 syntax:
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactBootstrap from 'react-bootstrap'
import GreeterMessage from 'GreeterMessage');
import GreeterForm from 'GreeterForm');
// sets the default values for props
Greeter.defaultProps = {
name: 'React',
message: 'This is the default message!'
};
class Greeter extends React.Component {
constructor(){
super();
// sets the initial state
this.state = {
name: this.props.name,
message: this.props.message
};
// due to this not being bound intrinsically to event handlers,
// it's advisable to do it here so that the reference to
// this.setState works as expected:
this.handleNewData = this.handleNewData.bind(this);
}
handleNewData(updates) {
// `this` is not automatically bound to event handlers in ES6
// Ensure that it is bound by using `.bind` (see constructor)
// OR with ES6 arrow functions
this.setState(updates);
}
render() {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
Issue is you are mixing es5 and es6 way of writing the react component. I will suggest you to write in es6. Pasted useful links in the last, refer those links for more details.
Write it like this:
class Greeter extends React.Component {
constructor(){
super();
this.state = {
name: this.props.name,
message: this.props.message
}
this.handleNewData = this.handleNewData.bind(this);
}
handleNewData (updates) {
this.setState(updates);
}
render () {
var name = this.state.name;
var message = this.state.message;
return (
<div>
<GreeterMessage name={name} message={message}/>
<GreeterForm onNewData={this.handleNewData}/>
</div>
);
}
};
Greeter.defaultProps = {
name: 'React',
message: 'This is the default message!'
};
Links:
DefaultProps
es6 class
React DOC
No Autobinding of methods

Categories

Resources