How to properly import/export components in React Native? - reactjs

I'm trying to export initial component, but all the time I'm getting Invariant Violation error:
Is there any better way to export my HMAPP component and import it inside App.js?
Error image:
Error screen
Here is my App.js:
import HMAPP from './app/HMAPP';
export default HMAPP;
Here is my HMAPP component:
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import { Navigation } from 'react-native-navigation';
import Mapbox from '#mapbox/react-native-mapbox-gl';
import { registerScreens } from './screens';
import store from './store/configureStore';
import { appInit, getInitialScreen } from './appInit';
import { handleErrorObject } from './lib/handleError';
Mapbox.setAccessToken('pkaeda324234');
const persistor = persistStore(
store,
null,
() => {
registerScreens(store, Provider);
appInit(store)
.then(() => {
const initialScreen = getInitialScreen(store.getState());
Navigation.startSingleScreenApp({
screen: {
screen: initialScreen,
},
passProps: {
persistor,
},
drawer: {
left: {
screen: 'DrawerMenuScreen',
},
},
appStyle: {
orientation: 'portrait',
},
});
})
.catch((error) => {
handleErrorObject('Error initializing app', error);
});
},
);

According to the docs of export and import, to externalize something inside one .js file, you need to use export. Once your module is exported, you can import him and use anywhere you want inside another .js files, for example.
So, in your HMAP.js file you'll need to export your const like this:
const persistor = persistStore( ... )
export default persistor;
and if you want to export more than one, you can export an object like this:
const persistor = persistStore( ... )
const persistor2 = persistStore2( ... )
export { persistor, persistor2 };
With your content exported, you can import it now on your App.js file:
import persistor from './app/HMAPP'; // use it when you exported with "default"
or
import { persistor1, persistor2 } from './app/HMAPP';
you could also import everything inside that file:
import * as persistors from './app/HMAPP';
Hope it helps someway.

In React Native, If you want to use your child component in other parent component then you have export that child component and import child component in parent component.
Else,
you declare your component with only class name, but in this way you can not use that component in any where.
Ex:
class Test extends React.Component {
}

Related

Failing to mock child react component in tests

There are a bunch of articles and examples about this one, but for some reason, nothing seems to work.
I have a react component that has a child component. And, for simplicity's sake, I want to mock the child component in the test.
The component looks like this:
...
import { ProjectTeam } from '../../assignment/project-team/component';
export const ProjectOverview: React.FC<ProjectOverviewProps> = ({ projectId }) => {
...
return (
<>
...
<Box flex={1}>
<ProjectTeam projectId={projectId} />
</Box>
...
</>
);
};
The ProjectTeam component:
export const ProjectTeam: React.FC<ProjectTeamProps> = ({ projectId }) => {
// just a standard component...
};
And here is the test:
import React from 'react';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { render } from '#testing-library/react';
import { I18nextProvider } from 'react-i18next';
import { generateProject } from '../../testing/generators/project';
import { ProjectOverview } from './component';
import { NGStateProvider } from '../../react/providers/route-provider/component';
import { testAngularRouter } from '../../testing/testAngularRouter';
import { DefaultProjectCollection, DefaultUtilizationCollection } from '../store/model';
import { DefaultApaActionCollection } from '../../apa/model';
import i18n from '../../testing/i18n';
import thunk from 'redux-thunk';
describe('ProjectOverview', () => {
let mockStore = null;
const project = generateProject();
beforeEach(() => {
jest.mock('../../assignment/project-team/component', () => ({ ProjectTeam: 'ProjectTeam' }));
mockStore = configureMockStore([thunk])({
projects: { DefaultProjectCollection, ...{ entities: { [project.id]: project } } },
toolUtilizations: DefaultUtilizationCollection,
apaActions: DefaultApaActionCollection,
});
});
test('renders correctly', () => {
const { asFragment } = render(
<NGStateProvider router={testAngularRouter}>
<Provider store={mockStore}>
<I18nextProvider i18n={i18n}>
<ProjectOverview projectId={project.id} />
</I18nextProvider>
</Provider>
</NGStateProvider>,
);
expect(asFragment()).toMatchSnapshot();
});
});
My assumption, that jest.mock(...) should simply replace the child component in test mode. However, it does not. The whole component is trying to render as is.
Here is one of the articles I was referring to: https://thoughtbot.com/blog/mocking-react-components-with-jest
Try moving the jest.mock call outside. I would say right at the top, just before and outside the describe section.
Jest needs to know about mocked component before it starts executing the test file in question.
The article which you reference, has this info,
Alternatively, you can put it within a __mocks__ folder next to the component if that is your preference.

Need help! React Component Export not working >_<

Im having this issue where even though I'm exporting both components
SearchBar & MainCard I keep getting this error message in my
App.js file. Any feedback is appreciated!
Error:
./src/App.js - Attempted import error: 'MainCard' is not exported from './components/ui-componets/SearchBar'.
App.js
import React, { Component } from 'react';
import { Container, Theme } from '#customLibrary/core'
import { connect } from 'react-redux';
import { fetchComponent } from './actions';
import TopMenu from './components/ui-componets/TopMenu';
import {SearchBar,MainCard} from './components/ui-componets/SearchBar';
class App extends Component {
state = {
visible: true,
width: 13,
}
handleClick = () => {
this.setState({ visible: !this.state.visible, width: 16 })
}
render() {
const { userData } = this.props;
const { visible } = this.state;
return <Theme>
<Container width='3379px'>
</Container>
<Container width='3379px'>
<TopMenu onClick={this.handleClick} userData={userData} />
</Container>
<Container width='3379px'>
<SearchBar />
</Container>
<Container width='3379px'>
<MainCard/>
</Container>
</Theme>
}
}
const mapStateToProps = (state) => {
return {
userData: state.user
}
}
export default connect(mapStateToProps, { fetchComponent })(App);
SearchBar.js
import React, { Component } from 'react';
import { IS_FETCHING_DBUSERS, FETCH_DBUSERS_SUCCESS, IS_FETCHING_ROLES, FETCH_ROLES_SUCCESS, IS_FETCHING_RESOURCES, FETCH_RESOURCES_SUCCESS } from '../../actions/keys';
import { users, Roles, Resources } from '../../actions/URI';
import { fetchComponent } from '../../actions/index';
import { connect } from 'react-redux';
import _ from 'lodash';
import {
Theme,
Grid, Form, Icon, Container, Loader,
Card, Typography, Tabs
} from '#customLibrary/core';
class SearchBar extends Component {
...
}
class MainCard extends Component {
...
}
const mapStateToProps = state => {
return {
Users: state.users,
roles: state.roles,
resources: state.resources,
}
}
export default connect(mapStateToProps, { fetchComponent })(SearchBar,MainCard);
import {SearchBar,MainCard} from './components/ui-componets/SearchBar';
You have used default export while exporting, but using the syntax for named imports while importing.
import CustomName from './components/ui-componets/SearchBar';
should work
Issue: You've not correctly exported MainCard, and you export them as a default export (i.e. only one component is exported), but you import them as named exports.
export default connect(mapStateToProps, { fetchComponent })(SearchBar,MainCard);
Solution: From what I know, the connect HOC can only decorate a single component at a time. If you want to export both then you'll need to connect both individually as named exports (i.e. remove the default keyword.
export const ConnectedSearchBar = connect(mapStateToProps, { fetchComponent })(SearchBar);
export const ConnectedMainCard = connect(mapStateToProps, { fetchComponent })(MainCard);
Now the import in App will work
import { SearchBar, MainCard } from './components/ui-componets/SearchBar';

The component for route must be a React component

The component for route 'Feed' must be a React component.
I've checked most of the other similar questions here but the majority of them are due to basic syntax (which maybe I have too but am blind to!). I've removed chunks of code that aren't relevant to this issue (navigationOptions and other screens) and can still reproduce the error with just the below:
./navigators/AppNavigator.js
import { createStackNavigator, createAppContainer, createBottomTabNavigator } from 'react-navigation';
import { FeedScreen } from '../screens/FeedScreen';
const FeedStack = createStackNavigator({
Feed: FeedScreen,
});
const DashboardTabNavigator = createBottomTabNavigator(
{
FeedStack
}
);
const DashboardStackNavigator = createStackNavigator(
{
DashboardTabNavigator: DashboardTabNavigator
}
);
const AppContainer = createAppContainer(DashboardStackNavigator);
export default AppContainer;
./screens/DashboardScreen.js
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import AppContainer from '../navigators/AppNavigator';
class DashboardScreen extends Component {
render() {
return (
<AppContainer />
);
}
}
export default DashboardScreen;
./screens/FeedScreen.js
import React from 'react';
import { View } from 'react-native';
export default class FeedScreen extends React.Component {
render() {
return (
<View>
</View>);
}
}
Any idea what I've done wrong here?
You have a default export for FeedScreen ... not a named export:
Try this:
import FeedScreen from '../screens/FeedScreen';
import { FeedScreen } from '../screens/FeedScreen'
You cannot importe like this if you re exporting by default.
Remove your default export or do replace your importe like this :
import FeedScreen from '../screens/FeedScreen'
You are using export default statement, that means you can´t import like that, you should provide a variable to store the component.
import Component from 'defaultexport'

When starting React Native app, I'm error that functions are not valid as React child

I'm trying to start my App with react-native-navigation and persistStore from redux persistStore.
I'm getting warning that functions are not valid as React child.This may happen if you return a Component instead of from render.
Is there any workaround to start this initial screen, recently I've added startApp function and call it inside render.
Here is my initial component for starting app:
import React, { Component } from "react";
import { Provider } from "react-redux";
import { View, Text } from "react-native";
import { persistStore } from "redux-persist";
import { Navigation } from "react-native-navigation";
import Mapbox from "#mapbox/react-native-mapbox-gl";
import { registerScreens } from "./screens";
import store from "./store/configureStore";
import { appInit, getInitialScreen } from "./appInit";
import { handleErrorObject } from "./lib/handleError";
Mapbox.setAccessToken("pk.eyJ123425KKbcgNww");
export default class App extends Component {
startApp = () => {
const persistor = persistStore(store, null, () => {
registerScreens(store, Provider);
appInit(store)
.then(() => {
const initialScreen = getInitialScreen(store.getState());
Navigation.startSingleScreenApp({
screen: {
screen: initialScreen
},
passProps: {
persistor
},
drawer: {
left: {
screen: "DrawerMenuScreen"
}
},
appStyle: {
orientation: "portrait"
}
});
})
.catch(error => {
handleErrorObject("Error initializing app", error);
});
});
};
render() {
return <View>{this.startApp}</View>;
}
}
There are two things wrong with your code.
startApp is a function and in order to render the JSX returned from any function you need to call it as {this.startApp()}
You do not have any JSX to be returned inside startApp, since it is just setting the values to the persistStore and would contain a persistor object.
I suggest you should take a look at the docs and this article to know more about the usage of react-native-navigation

Use component with connect() - Cannot read property 'displayName' of undefined

I have a strange problem related to the function ‘connect’ and a presentational component
import React from 'react';
import { withRouter } from 'react-router';
import { connect } from 'react-redux';
import * as optionGroupActions from 'actions/optionGroupActions';
import OptionGroupForm from 'components/optionGroup/OptionGroupForm';
const mapDispatchToProps = (dispatch, ownProps) => {
return {
saveOptionGroup: (optionGroup) => {
dispatch(optionGroupActions.fetchSaveOptionGroup(optionGroup));
},
onClickCancel: () => {
ownProps.router.push('/product/options');
}
};
};
const OptionGroupAddContainer = connect(
null,
mapDispatchToProps
)(OptionGroupForm);
export default OptionGroupAddContainer;
This works but if I change the import with this
import { OptionGroupForm } from 'components’;
I got this error:
connect.js:57Uncaught TypeError: Cannot read property 'displayName' of undefined
components/index.js looks like
// OptionGroups
import OptionGroupForm from 'components/optionGroup/OptionGroupForm';
export {
OptionGroupForm
};
if you want to import like below
import { OptionGroupForm } from 'components’;
you have to use resolve in your build process config file to define the path variable,
or you can just import it like below
import { OptionGroupForm } from './components’;
EDIT: Your components/index.js should look like below
import OptionGroupForm from './optionGroup/OptionGroupForm';
export {
OptionGroupForm
};
Depending on your build process, you may need to specify your import like this in order to have the source be treated as a relative path rather than an npm module name:
import { OptionGroupForm } from './components’;

Resources