Write asynccomponent in react router config for lazy loading - javascript

I'm new to react. Trying to lazy load the components. Am using server side rendering along with react router config. I need to lazy load the components.
asyncComponent.js
import React, { PureComponent } from 'react';
export default class extends PureComponent {
constructor(props) {
super(props);
this.state = {
Component: null
}
}
componentWillMount() {
if(!this.state.Component) {
this.props.moduleProvider().then( ({Component}) => this.setState({ Component }));
}
}
render() {
const { Component } = this.state;
//The magic happens here!
return (
<div>
{Component ? <Component /> : ''}
</div>
);
}
};
Route.js
import React from 'react';
import App from './app';
import asyncComponent from './asyncComponent';
const Home = asyncComponent.moduleProvider(import('./components/Home'));
const routes = [{
component: App,
routes: [
{
path : '/',
exact: true,
component: Home
}
]
}];
export default routes;
I have refered the example from [https://github.com/rubenspgcavalcante/react-webpack-lazy-loading.git][1]
This is throwing exception. Is this the correct way to do it?

Related

How to solve "Can't find variable: App" in React Native?

I am new to React Native and I don't understand how to solve this problem. I already installed react-native-gesture-handler.
I am getting this error in the command:
Accessing view manager configs directly off UIManager via UIManager['getConstants'] is no longer supported. Use UIManager.getViewManagerConfig('getConstants') instead.
This is a part of the code:
import { createAppContainer, DrawerNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Home from "./src/screens/Home.js";
import first from "./src/screens/first.js";
import React from 'react';
class App extends React.Component{
render(){
return(
<RootStack/>
)
}
}
const RootStack = createStackNavigator ({
Home:{screen:Home,
navigationOptions: {
header: null
}},
first:{screen:first,
navigationOptions: {
header: null
}}
});
//const App = createAppContainer(RootStack);
export default App;
I think this way is better:
const AppNavigator = createSwitchNavigator({
Auth: {
screen: Auth
},
Root: {
screen: BottomTabNavigator
}
})
const AppContainer = createAppContainer(AppNavigator)
const App = () => {
return (
<AppContainer />
)
}
export default App
OR
if it didn't work then you better check your index.js file whether you imported App Component (Root component) correctly or not?

How to implement Context API in React Native

I just start looking for changing theme globally, and found Context can do that,
but I've a problem to implement the example code to my react native project,
I've tried this code:
//themeContext.js
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
})
//App.js
import React, { Component } from 'react';
import {InitialScreen} from './routes/routes';
import { ThemeContext } from './Component/themeContext';
export default class App extends Component {
constructor(props) {
super(props);
this.state={
theme:themes.light,
toggleTheme:this.toggleTheme
}
this.toggleTheme=()=>{
this.setState(state=>({
theme:state.theme === themes.dark ? themes.light : themes.dark
}))
}
}
render() {
console.disableYellowBox = true;
return (
<ThemeContext.Provider value={this.state}>
//this is Login.js
<InitialScreen/>
</ThemeContext.Provider>
);
}
}
//Login.js
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { ThemeContext } from '../Component/themeContext';
export default class Login extends Component {
render() {
return (
<ThemeContext.Consumer>
{({theme, toggleTheme})=>{
<View style={{backgroundColor:theme.background}}>
<Text>{this.state}</Text>
</View>
}}
</ThemeContext.Consumer>
);
}
}
but i have an error Can't find variable: Component, i don't know where should i put import React from 'react'; cause i think I've add Component var in app.js and login.js
any help would be appreciate
Replace next string in the top of your Login.js instead of
import React from 'react';
with
import React, { Component } from 'react';
Another way is to replace
export default class Login extends Component {
}
with
export default class Login extends React.Component {
}
In App.js updated your App component class defintion by replacing Component with React.Component as shown:
export default class App extends React.Component {
/* existing component code */
}
Make the same change in Login.js as well:
export default class Login extends React.Component {
/* existing component code */
}
These changes will cause the Login and App components to extend from the Component class as defined on the React object exported from 'react'.
Your problem in themeContext.js file
you use createContext() but you don't import React so you will get can't find React
it's should be like this
import React from 'react';
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
And in Login.js
import React,{Component} from 'react';

Uncaught Error: Could not find "store" in either the context or props of Connect(Form())

I'am using redux, react-router-redux and redux-form in my code. Code has a Provider, Connected router and Mini component. Mini component includes Switch and some components, which depends on route.
Index.js
...
import { Provider } from 'react-redux'
import { ConnectedRouter, routerMiddleware } from 'react-router-redux'
import createBrowserHistory from 'history/createBrowserHistory'
import Reducers from './reducers'
const history = createBrowserHistory({ basename: 'mini' })
const middlewareRouter = routerMiddleware(history)
const store = createStore(Reducers, applyMiddleware(middlewareRouter))
render(<Provider store={store}>
<ConnectedRouter history={history}>
<Mini/>
</ConnectedRouter>
</Provider>, document.getElementById('root'))
Mini.js
import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom'
...
import NavigationContainer from './containers/navigation'
import CategoryContainer from './containers/category'
class Mini extends Component {
render () {
return (<main>
<Switch>
<Route path="/navigation" component={NavigationContainer}/>
<Route path="/category" component={CategoryContainer}/>
...
</Switch>
<LoadContainer/>
<div id="form"></div>
</main>)
}
}
All components in Switch section has a button. Clicking on the button can render a form.
...
import FormCreate from './formcreate'
class Topbar extends Component {
constructor (props) {
super(props)
this.handleClickCreate = this.handleClickCreate.bind(this)
}
handleClickCreate (e) {
e.preventDefault()
render(<FormCreate/>, document.getElementById('form'))
}
...
}
But when I click on button error appear Uncaught Error: Could not find "store" in either the context or props of "Connect(Form(FormCreate))"
How can I fix the problem? Thanks in advance!
PS Reducers.js
import { combineReducers } from 'redux'
import { routerReducer as reducerRouter } from 'react-router-redux'
import { reducer as reducerForm } from 'redux-form'
const Reducers = combineReducers({
...
router: reducerRouter,
form: reducerForm
})
PSS FormCreate.js
import React from 'react'
import { Field, reduxForm } from 'redux-form'
...
const FormCreate = (props) => {
const { error, handleSubmit, pristine, reset, submitting } = props
return (
...
)
}
export default reduxForm({
form: 'create',
validate
}) (FormCreate)
I think the problem here is that you are trying to render FormCreate create another app within html element form that does not have access to the redux store, resulting in the error that you see.
What I would do is set up a reducer that handle whether or not I should render FormCreate then render it in component in your app like in LoadContainer.
Topbar.js
class Topbar extends Component {
constructor (props) {
super(props)
this.handleClickCreate = this.handleClickCreate.bind(this)
}
handleClickCreate (e) {
e.preventDefault()
// dispatch action to reducer to tell store to display FormCreate
}
...
}
LoadContainer.js
class LoadContainer extends Component {
// ... rest of code
render() {
// get shouldDisplayForm from redux store
const { shouldDisplayForm } = this.props;
return (
//... rest of component
{ shouldDisplayForm && <FormCreate> }
);
}
}
Alternatively, if you want to render FormCreate in html element 'form', you can put the store in a file so that you can require it in many files. Then render FormCreate with Provider like what you've done Index.js.

React Router - new component not being loaded

So it's my first time setting something like this up and I'm struggling a little bit.
I used https://github.com/reactjs/react-router/tree/master/examples/huge-apps as my source of learning and am trying to set up a very basic layout for a react application.
What seems to be happening is that react isn't re-rendering after a path change therefore nothing ever gets added to the dom
When I click on the go to home component Link the URL bar changes but no DOM changes occur...
Here is my code [i'm leaving out my directory structure since i don't think it's important for the problem]
index.jsx: Load up the react app and get all routes
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import Routes from './app/Routes.js';
render(
<Router
history={browserHistory}
routes={Routes}
/>,
document.querySelector('.js-mount-point')
);
Routes.js: Constant to keep all of my routes so that I don't have to manually specify them in index.js
import App from './App.jsx';
import Home from '../routes/Home/Home.js';
const Routes = {
path: '/',
component: App,
childRoutes: [
Home,
],
};
export default Routes;
App.jsx: Parent most component for my app
import React from 'react';
import { Link } from 'react-router';
const App = props => {
console.log(props);
return (
<div>
<h1>Hello World!</h1>
<p><Link to="#/home">Go to Home Component</Link></p>
{props.children}
</div>
);
};
export default App;
Home.js Grab all my route information and getComponent lives here
const HomeRoute = {
path: 'home',
title: 'Home',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./HomeComponent.jsx').default);
});
},
};
export default HomeRoute;
HomeComponent.jsx my very basic home component
import React from 'react';
const HomeComponent = () => (
<div>
<h2>Welcome Home</h2>
</div>
);
export default HomeComponent;
Edit1: Made App.jsx pure function
Edit2: Fixed Routes.js
Edit3: Fixed Home.js
Edit4: Final fix,
const HomeComponent =
changed to
const HomeComponent = () => (
You App should be a component not a function returning an object. Right now you are mixing two approaches.
Either a function (stateless component)
import React from 'react';
import { Link } from 'react-router';
const App = props => {
console.log(props.children);
return (
<div>
<h1>Hello World!</h1>
<p><Link to="/home">Go to Home Component</Link></p>
{props.children}
</div>
);
};
export default App;
Or a statefull component that has render method
import React, { Component } from 'react';
import { Link } from 'react-router';
class App extends Component {
render() {
console.log(this.props.children);
return (
<div>
<h1>Hello World!</h1>
<p><Link to="/home">Go to Home Component</Link></p>
{this.props.children}
</div>
);
}
};
export default App;
Same with HomeComponent
const HomeComponent = () => (
<div>
<h2>Welcome Home</h2>
</div>
);
And you need to fix route config as well
const HomeRoute = {
path: 'home', //no # needed
title: 'Home',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./HomeComponent.jsx').default);
});
},
};
Ohh, and I think you need.
const Routes = {
path: '/',
component: App,
childRoutes: [
Home
],
};

React.js test fails on finding components

I have an app build on React, Redux and React-router. I'm writing test using React TestUtils and I found that from the tests you can see below.
The first expect works: expect(nav).to.have.length(1);
but the second one expect(modal).to.have.length(1);
fails with:
AssertionError: expected [] to have a length of 1 but got 0
App.js:
import React, { Component, cloneElement, PropTypes } from 'react';
import ContactsList from './contactsList';
import Nav from './nav';
import Modal from './modal';
import Header from './header';
import HomeIndex from './homeIndex';
import ErrorBox from './errorBox';
import ImmutablePropTypes from 'react-immutable-proptypes';
export default class App extends Component {
render = () => {
const { actions, contacts, router } = this.props;
return (
<div>
<Nav />
<div className="container">
<ErrorBox error={contacts.getIn(['error', 'errorMessage'])} show={contacts.getIn(['error', 'showError'])} />
<Header />
<div className="contacts-list-container">
<ContactsList contacts={contacts} />
<Modal open={contacts.get('showSpinner')} />
{ cloneElement(this.props.children || <HomeIndex/>, { contacts: contacts ,
addContact: actions.addContactReq,
getContact: actions.getContact,
contact: contacts.get('contact'),
router: router,
deleteContact: actions.deleteContact,
editContact: actions.editContact }) }
</div>
</div>
</div>
);
}
}
App.propTypes = {
actions: PropTypes.object.isRequired,
contacts: ImmutablePropTypes.map.isRequired,
router: PropTypes.object.isRequired
};
App-spec.js:
import React from 'react';
import { renderIntoDocument, scryRenderedDOMComponentsWithTag } from 'react-addons-test-utils';
import { expect } from 'chai';
import App from '../components/app';
import { Map } from 'immutable';
describe('app', () => {
it('renders properly', () => {
const component = renderIntoDocument(
<App actions={{}} router={{}} contacts={ Map({
showSpinner: false,
error: Map({
showError: false,
errorMessage: ''
}),
contacts: Map(),
contact: Map()
}) } />
);
const nav = scryRenderedDOMComponentsWithTag(component, 'Nav');
const modal = scryRenderedDOMComponentsWithTag(component, 'Modal');
expect(nav).to.have.length(1);
expect(modal).to.have.length(1);
});
});
scryRenderedDOMComponentsWithTag looks for actual HTML elements in the component DOM. You want to use scryRenderedComponentsWithType to find rendered React components:
const modal = scryRenderedComponentsWithType(component, Modal);
See https://facebook.github.io/react/docs/test-utils.html#scryrenderedcomponentswithtype
Your Nav call probably works because you have a <nav> HTML element in your Nav React component.
scrying needs a component reference iirc. So:
import Modal from './components/modal';
// Then later:
const modal = scryRenderedComponentsWithType(component, Modal);
This will look for instances of the actual component.

Categories