Exporting component using i18n's useTranslation and redux's connect HOCs - javascript

My App has used Redux for a long time, with the component exports looking like
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
I'm now introducing i18n's translation library and would like to use the HOC that is included with the useTranslation.
I've attempted a few different ways and seen that Redux has a connect piece of functionality that is supposed to combine HOCs if I understand correctly, however I cannot get this to work.
export default connect(useTranslation(), connect(mapStateToProps, mapDispatchToProps))(MyComponent);
When I load the browser I am shown:
Uncaught ReferenceError: process is not defined
Am I missing something here?

useTranslation is not a HOC, you want withTranslation. That will look like this:
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(MyComponent));
Or, since the order doesn't matter:
export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(MyComponent));
Nesting multiple HOCs can be hard to read, so it may be easier to use a compose utility function. Redux even includes one:
import { compose, connect } from 'redux';
//...
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withTranslation()
)(MyComponent);

Related

Export React component with two property

I'm using MaterialUI and I have to export my components like this:
import withStyles, { WithStyles } from "#material-ui/core/styles/withStyles";
...
export default withStyles(styles)(Users);
Now I started to use i18next to use internationalization in my project but it want me to export my component like this:
export default translate("common")(Users);
The question is how can I satisfy both? How can I export with withStyles and translate?
Any help is appreciated
Both of those pieces of code produce a new component, so you can feed the result of one into the other. Done in one line, it would look like this:
export default withStyles(styles)(translate("common")(Users));
Or if it makes it easier to follow, here it is split on two lines.
const TranslatedUsers = translate("common")(Users);
export default withStyles(styles)(TranslatedUsers);
The purpose of higher-order components is to provide a way for components to be efficiently composed:
export default translate("common")(
withStyles(styles)(Users)
);
It can be flattened with composition helpers, e.g. recompose:
import { compose } from 'recompose'
export default compose(
translate("common"),
withStyles(styles)
)(Users);

JS `import` is undefined, potentially circular import issue?

Preface
I'm using create-react-app to generate an application.
Problem
TodoList === undefined
Code
components/index.js
export { default as App } from './App/App.js';
export { default as TodoList } from './TodoList/TodoList.js';
containers/index.js
export { default as VisibleTodoList } from './VisibleTodoList.js';
components/App/App.js
import { VisibleTodoList } from '../../containers/index.js';
containers/VisibleTodoList.js
import { TodoList } from '../components/index.js';
components/TodoList/TodoList.js
export default function TodoList({ todos, onTodoClick }) { ... }
TodoList is now undefined. I believe it may have something to do with the fact that I have some sort of circular issue.
The thing is, if inside containers/VisibleTodoList.js I import using the following method, everything works fine.
import TodoList from '../components/TodoList/TodoList.js';
What is so special that breaks the import, if I try to import using a 'middleman' (the components/index.js file).
Full code
I have created a CodeSandbox that contains my full code, as it stands in my application. The application is pretty simplistic, but more complicated than I have outlined here.
https://codesandbox.io/s/m54nql1ky9
The problem is caused by the order of exports in your components/index.js file.
export { default as App } from './App/App.js';
export { default as TodoList } from './TodoList/TodoList.js';
Since App.js imports VisibleTodoList which needs to import TodoList and pass it to the redux connect function before it can export itself, you end up with a conflict.
I'm not sure if this is a implementation quirk of babel, or if this is a logical result from how the ES import spec is defined.
In any case, changing the order of exports fixes the bug.
export { default as TodoList } from './TodoList/TodoList.js';
export { default as App } from './App/App.js';
As a rule of thumb, if you can't refactor your files to avoid the import loop, you should put the outer layer component last in the list, since it might rely on imports higher up in the list.
Full working codesandbox here: https://codesandbox.io/s/74mlwnwyy1

JavaScript export 2 functions

I'm using React, Redux and now trying to include Material-UI. The Reduct and the Matrial-UI libs are showing example code that has an export at the end.
Redux:
export default connect(mapStateToProps, actions)(myComponent)
Material-UI:
export default withStyles(styles)(myComponent);
When I'm trying to bring both exports together, I have to get rid the default. So I thought it should look like this
This does not work:
export {
connect(mapStateToProps, actions)(myComponent),
withStyles(styles)(myComponent)
}
Error:
"Syntax error: Unexpected token, expected , (120:15)
export {connect(mapStateToProps, actions)(myComponent)}
^
This doesn't work:
I tried to name the function, but then the function wasn't called, for some reasons I don't know.
import * as myConnect from 'react-redux'
...
export const connect = myConnect.connect(mapStateToProps, actions)(View)
I don't know what is happening 'under the hood' so I'm stuck. Any help is appreciated :-)
EDIT
I haven't found a solution yet but I got around the problem. I split the component (myComponent) into an extra file. The design is event better like that, now it distinguishes between pure components and containers.
There is another solution that a lot of people will need at one point to build HOC (Higher order component). I will suggest using Recompose utility (if you are ok to add another package to your project). Here is a link to great article about it on medium.
So if I will be writing your code here is how I will write to build HOC:
import compose from 'recompose/compose';
//...your component code here
export default compose(withStyles(styles),
connect(mapStateToProps, actions))(myComponent);
{
connect(mapStateToProps, actions)(myComponent),
withStyles(styles)(myComponent)
}
This isn't a valid object; you're missing the keys.
{
myConnectedComponent: connect(mapStateToProps, actions)(myComponent),
myStyledComponent: withStyles(styles)(myComponent)
}
Make them named exports:
export const myConnect = connect(mapStateToProps, actions)(myComponent);
export const myStyles = withStyles(styles)(myComponent);
Then use named imports:
import {myConnect} from './yourscript';

You must pass a component to the function returned by connect. Instead received undefined

The code below gives
Uncaught Error: You must pass a component to the function returned by connect. Instead received undefined
List.js
import React from 'react';
import { connect, bindActionCreators } from 'react-redux';
import PostList from '../components/PostList'; // Component I wish to wrap with actions and state
import postList from '../Actions/PostList' //Action Creator defined by me
const mapStateToProps = (state, ownProps) => {
return state.postsList
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({"postsList":postList},dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(PostList);
PostList.js
import React from 'react'
export const PostList = (props) => {
return <div>List</div>
}
Please help me with a solution?
You are doing import PostList from '../components/PostList'; so you need to use export default in your PostList.js file.
Otherwise you need to do import { PostList } from '../components/PostList';.
To whoever is interested, here is a nice article about es6 import/export syntax: http://www.2ality.com/2014/09/es6-modules-final.html
Not related to the asker specifically, but if you're facing this error, it's worth to check if you have the connect() syntax right:
const PreloadConnect = connect(mapStateToProps, {})(Preload);
export default PreloadConnect;
Note that Preload, is passed as a IIFE parameter.
More details can be found here.
There might be three reasons, that are summarized as follows:
Circular dependencies between components
Wrong usage of export and export default then imported the wrong way
Used the connect function wrongly, passed the wrong parameters
In my case is was Circular dependencies, and the circular-dependency-plugin helped me fix it.
In my case it was Expo server that sometimes doesn't catch filesaves on Windows (probably) and it was seening old version of the component I've tried to connect (I had no export there yet probably). Re-saving my component without really touching anything fixed the issue.
Restarting Expo server with cleaned cache would probably help as well.
In my case, it was because of the usage of enums (TypeScript).
Try without enums in your code.
Reason : Enums can go undefined during runtime.
Link to Related Question
Hope it solves your problem :)

Export multiple wrapper functions in Javascript ES6

I'm using react-komposer to wrap React components with a data fetching wrapper.
It is very basic and I'd want to wrap multiple components in Meteor. But I can't figure out what the export pattern is?
Here is what I have (and gives me an "Unexpected Token" error - probably obvious if you understand this well!):
// myContainer.jsx
import Component1 from './Component1.jsx';
import Component2 from './Component2.jsx';
function composer(props, onData) {
if (Meteor.subscribe('SingleTodoLists').ready()) {
const todoList = todoLists.find({}).fetch();
onData(null, { todoList });
}
}
export composeWithTracker(composer, Loading)(Component1);
export composeWithTracker(composer, Loading)(Component2);
And I'd like to import them like this:
import { Component1, Component2 } from './myContainer.jsx';
This wrapper syntax is not really clear for me, so I'm unsure about what to try. Playing with export default and other variations yielded no result so far.
If you don't use default exports, you need to name the things you export:
export const TrackedComponent1 = composeWithTracker(composer, Loading)(Component1);
export const TrackedComponent2 = composeWithTracker(composer, Loading)(Component2);
If you use default export instead you can omit the name, e.g.
export default composeWithTracker(composer, Loading)(Component1);
But you can only define one default export per module
See the documentation for the ES6 export syntax: https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export
Update:
If you want to keep the original export names:
import _Component1 from './Component1.jsx';
import _Component2 from './Component2.jsx';
//... you code here
export composeWithTracker(composer, Loading)(_Component1);
export composeWithTracker(composer, Loading)(_Component2);
Because Component1.jsx uses a default exports, when you import it you can rename it as you want (e.g. _Component1, UntrackedComponent1, ...). Without a default export, you could have used import { Component1 } as _Component1 instead.

Categories

Resources