React lazy does not cause splitting bundle in chunks - reactjs

As in the title, I'm trying to use React.lazy feature which works in my my other project. But not in this one, I don't know what I'm missing here. All works just fine, no errors, no warnings. But for some reason I don't see my bundle split in chunks.
Here's my implementation:
import React, { Component, Suspense } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { getApps } from '../../actions/apps';
import './_apps.scss';
const AppItemComponent = React.lazy(() => import('../AppItem'));
class Apps extends Component {
componentDidMount() {
const { getApps } = this.props;
getApps(3);
}
renderAppItem = () => {
const { apps } = this.props;
return apps && apps.map((item, i) => {
return (
<Suspense fallback={<div>loading...</div>} key={i}>
<AppItemComponent
index={i + 1}
item={item}
/>
</Suspense>
);
});
};
render() {
const { apps } = this.props;
return (
<div className="apps__section">
<div className="apps__container">
<div className="apps__header-bar">
<h3 className="apps__header-bar--title">Apps</h3>
<Link className="apps__header-bar--see-all link" to="/apps">{`see all (${apps.length})`}</Link>
</div>
{this.renderAppItem()}
</div>
</div>
);
}
}
const mapStateToProps = ({ apps }) => {
return { apps };
};
const mapDispatchToProps = dispatch => {
return {
getApps: quantity => dispatch(getApps(quantity)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Apps);
I'm doing this in react-create-app app and in react v16.6, react-dom v16.6.
What am I missing here?

I also have the same problem, then I have resolved this case without using Suspense and lazy(try code below), and I can see chunks file. However, after using this way, I try changing my code again with Suspense and lazy. It works!!! and I don't know why it does. Hope that it works for someone find solution for this case.
1 - create file asyncComponent
import React, { Component } from "react";
const asyncComponent = (importComponent) => {
return class extends Component {
state = {
component: null,
};
componentDidMount() {
importComponent().then((cmp) => {
this.setState({ component: cmp.default });
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
};
};
export default asyncComponent;
2 - and in App.js, example:
const AuthLazy = asyncComponent(() => import("./containers/Auth/Auth"));
//Route
<Route path="/auth" component={AuthLazy} />

Check that your component is not imported somewhere with regular import: import SomeComponent from './path_to_component/SomeComponent';
Check that component is not re-exported somewhere. (For example in index.js (index.ts) file: export * from './SomeComponent') If so, just remove re-export of this component.
Check that your export your component as default or use code like this:
const SomeComponent = React.lazy(() => import('./path_to_component/SomeComponent').then((module) => ({ default: module.SomeComponent })));

Related

EditorJS is not showing in NextJS even it is loaded through SSR:false

so I am integrating EditorJs with the NextJs app I have done the initialization in the console it shows Editojs is ready but on the screen, it is not visible
can anyone please tell me what I am doing wrong I am sharing my code below
Editor.js
import { createReactEditorJS } from 'react-editor-js'
import { EditorTools } from './EditorTools';
import React, { useEffect } from 'react'
const Editor = () => {
const ReactEditorJS = createReactEditorJS();
return (
<div>
<ReactEditorJS holder="customEditor" tools={EditorTools}>
<div id="customEditor" />
</ReactEditorJS>
</div>
)
}
export default Editor
EditorTools.js
import Header from '#editorjs/header';
export const EditorTools = {
header: {
class: Header,
config: {
placeholder: 'Let`s write an awesome story! ✨',
},
},
};
Create.js
import React from 'react'
import dynamic from 'next/dynamic';
const EditorJSNoSSRWrapper = dynamic(import('../../../components/Editor/Editor'), {
ssr: false,
loading: () => <p>Loading ...</p>,
});
const create = () => {
return (
<div>
<EditorJSNoSSRWrapper />
</div>
)
}
export default create

How to fix problem with React-Redux(mapDispatchToProps() in Connect() must return a plain object. Instead received undefined.)

I ported my application to redux-thunk and the error started to appear in the console(
mapDispatchToProps() in Connect(UsersContainer) must return a plain object. Instead received undefined.).
But with the appearance of this error, nothing has changed. How to fix it?
Reducer:
import {getTeamApi} from "./api";
let date = {
teamDate: []
};
const realtorsDate = (state = date, action) => {
switch (action.type) {
case "GetTeam":
return {...state, teamDate: [...state.teamDate, ...action.team]};
default:
return state
}
}
export let GetTeam = (team) => ({
type: "GetTeam",
team
})
export default realtorsDate;
export const getTeamThunks = () => {
return (dispatch) => {
getTeamApi.then(response => {
dispatch(GetTeam(response.items));
});
}
}
Container component:
import {connect} from "react-redux";
import {getTeamThunks} from "../../store/realtorsDate";
import ScrollableAnchor from "react-scrollable-anchor";
import MainFourth from "./main-fourth";
import Photo from "../../Images/pivo-3.jpg";
import React from "react";
class UsersContainer extends React.Component {
render() {
return (
<section>
<ScrollableAnchor id={"team"}>
<h2>Наша команда</h2>
</ScrollableAnchor>
<div className="MainFourth">
{this.props.realtorsDate.map((el, i) => (
<MainFourth key={i} el={el} Photo={Photo}></MainFourth>))}
</div>
</section>
);
}
}
let MapStateToProps = (state) => {
return {
realtorsDate: state.realtorsDate.teamDate
}
}
let FourthContainerBlock = connect(MapStateToProps, getTeamThunks)(UsersContainer)
export default FourthContainerBlock
Component:
import React from "react";
import "./../../css/App.css";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import {faAt, faMobileAlt} from "#fortawesome/free-solid-svg-icons";
class MainFourth extends React.Component {
render() {
return (
<div className="team" key={this.props.i}>
<div className="about-team">
<h2 className="team-name">
{this.props.el.SecondName}
{this.props.el.Name}
</h2>
<h2 className="team-position">{this.props.el.Position}</h2>
<p><FontAwesomeIcon icon={faMobileAlt}></FontAwesomeIcon> : {this.props.el.Phone}</p>
<p><FontAwesomeIcon icon={faAt}></FontAwesomeIcon> : {this.props.el.Mail}</p>
</div>
<img className="TeamsPhoto" src={this.props.Photo} alt="" />
</div>
);
}
}
export default MainFourth;
Ty all
The error is actually pretty straight forward, getTeamThunks should return a js object and that should be synchronous. You can do asynchronous things in the action creators.
The second argument to connect is simply used to map the dispatch to props(the reason why most tend to name it as such).
For example, mapDispatchToProps can look like this:
const mapDispatchToProps = (dispatch) => {
return {
getTeamThunks: () => dispatch(actions.getTeamThunksData())
}
}
let FourthContainerBlock = connect(MapStateToProps, mapDispatchToProps)(UsersContainer)
Now the getTeamthunksData can be written like this:
export const getTeamThunksData = () => {
return (dispatch) => {
getTeamApi.then(response => {
dispatch(GetTeam(response.items));
});
}
}
In your component, you can dispatch it by using this.props.getTeamThunks(). Where you execute it depends on your requirements.

React - frontend component test with Jest

I've just written test file for my component, at the moment it's very rudimentary.. I'm quite inexperience in written test for frontend. I ran yarn test to this test file and it failed miserably..
Here is the message:
Unable to find an element with the text: Please review your billing details...
This is what I have so far for my test:
import React from 'react';
import { render, cleanup, waitForElement } from 'react-testing-library';
// React Router
import { MemoryRouter, Route } from "react-router";
import Show from './Show';
test('it shows the offer', async () => {
const { getByText } = render(
<MemoryRouter initialEntries={['/booking-requests/20-A1-C2/offer']}>
<Route
path="/booking-requests/:booking_request/offer"
render={props => (
<Show {...props} />
)}
/>
</MemoryRouter>
);
//displays the review prompt
await waitForElement(() => getByText('Please review your billing details, contract preview and Additions for your space. Once you’re happy, accept your offer'));
//displays the confirm button
await waitForElement(() => getByText('Confirm'));
});
and this is the component:
// #flow
import * as React from 'react';
import i18n from 'utils/i18n/i18n';
import { Btn } from '#appearhere/bloom';
import css from './Show.css';
import StepContainer from 'components/Layout/DynamicStepContainer/DynamicStepContainer';
const t = i18n.withPrefix('client.apps.offers.show');
const confirmOfferSteps = [
{
title: t('title'),
breadcrumb: t('breadcrumb'),
},
{
title: i18n.t('client.apps.offers.billing_information.title'),
breadcrumb: i18n.t('client.apps.offers.billing_information.breadcrumb'),
},
{
title: i18n.t('client.apps.offers.confirm_pay.title'),
breadcrumb: i18n.t('client.apps.offers.confirm_pay.breadcrumb'),
},
];
class Show extends React.Component<Props> {
steps = confirmOfferSteps;
renderCtaButton = (): React.Element<'Btn'> => {
const cta = t('cta');
return <Btn className={css.button} context='primary'>
{cta}
</Btn>
};
renderLeftContent = ({ isMobile }: { isMobile: boolean }): React.Element<'div'> => (
<div>
<p>{t('blurb')}</p>
{!isMobile && this.renderCtaButton()}
</div>
);
renderRightContent = () => {
return <div>Right content</div>;
};
render() {
const ctaButton = this.renderCtaButton();
return (
<StepContainer
steps={this.steps}
currentStep={1}
ctaButton={ctaButton}
leftContent={this.renderLeftContent}
rightContent={this.renderRightContent}
footer={ctaButton}
/>
);
}
}
export default Show;
what am I missing? Suggestions what else to add to my test file would be greatly appreciated!

TypeScript - invoking React prop with Enzyme

I'm trying to convert my Jest tests using Enzyme to TypeScript, but running into one particular case that I'm not sure how to handle. Basically, I'm trying to call a function that is passed as a prop to a sub-component. The error I'm seeing is:
spec/javascript/_common/components/sidebar_spec.tsx:85:5 - error TS2349:
Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures.
85 component.find(Link).at(0).prop('onNavigate')();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
How do I get past this error? Not sure if it's helpful, but more context for the test:
it('does not hide the sidebar after a link is clicked', () => {
const component = shallow(<Sidebar />);
component.find(Link).at(0).prop('onNavigate')();
component.update();
expect(component.find(Link)).toHaveLength(3);
});
And a chunk of code from the Sidebar component:
class Sidebar extends React.Component<any, any> {
...
hideIfMobile() {
const {mobile} = this.state;
if (mobile) { this.setState({visible: false}); }
}
render() {
const {visible} = this.state;
if (!visible) {
return (
<div className='sidebar sidebar--hidden'>
{this.sidebarToggle()}
</div>
);
}
const linkProps = {
baseClass: 'sidebar__link',
onNavigate: this.hideIfMobile,
};
return (
<div className='sidebar sidebar--visible'>
<h2 className='sidebar__header'>{'Menu'}{this.sidebarToggle()}</h2>
<hr className='sidebar__divider' />
<Link to='root' {...linkProps}><h2>{'FOCUS'}</h2></Link>
<Link to='tasks' {...linkProps}><h2>{'ALL TASKS'}</h2></Link>
<Link to='timeframes' {...linkProps}><h2>{'TIMEFRAMES'}</h2></Link>
</div>
);
}
}
the Link component is wrapped in react-redux:
import {connect} from 'react-redux';
import Link from 'src/route/components/link';
import {getRouteName} from 'src/route/selectors';
import {setRoute} from 'src/route/action_creators';
function mapStateToProps(state) {
return {routeName: getRouteName(state)};
}
export default connect(mapStateToProps, {setRoute})(Link);
and the actual component:
class Link extends React.Component<any, any> {
navigate(event) {
event.preventDefault();
const {onNavigate, params, setRoute, to} = this.props;
setRoute({name: to, ...params});
if (onNavigate) { onNavigate(); }
}
path() {
const {params, to} = this.props;
const pathParams = mapValues(params, value => value.toString());
return findRoute(to).toPath(pathParams);
}
className() {
const {baseClass, className, to, routeName} = this.props;
return classnames(
baseClass,
{[`${baseClass}--active`]: baseClass && routeName === to},
className,
);
}
render() {
const {children} = this.props;
return (
<a
href={this.path()}
className={this.className()}
onClick={this.navigate}
>
{children}
</a>
);
}
}
It turns out Link in this case was defined earlier in my test file as:
const Link = 'Connect(Link)';
I switched this to import the actual link container and it resolved the issue.
import Link from 'src/route/containers/link';

Implementing React Redux

I am slowly learning React and also learning to implement it with Redux. But I seem to have hit a road block. So this is what I have so far.
/index.jsx
import './main.css'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App.jsx'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import ShoppingList from './reducers/reducer'
let store = createStore(ShoppingList)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
/actions/items.js
import uuid from 'node-uuid'
export const CREATE_ITEM = 'CREATE_ITEM'
export function createItem(item) {
return {
type: CREATE_ITEM,
item: {
id: uuid.v4(),
item,
checked: false
}
}
}
/reducers/reducer.js
import * as types from '../actions/items'
import uuid from 'node-uuid'
const initialState = []
const items = (state = initialState, action) => {
switch (action.type) {
case types.CREATE_ITEM:
return {
id: uuid.v4(),
...item
}
default:
return state;
}
}
export default items
/reducers/index.js
UPDATE:
import { combineReducers } from 'redux'
import items from './reducer'
const ShoppingList = combineReducers({
items
})
export default ShoppingList
/components/Item.jsx
import React from 'react';
import uuid from 'node-uuid'
export default class Item extends React.Component {
constructor(props) {
super(props);
this.state = {
isEditing: false
}
}
render() {
if(this.state.isEditing) {
return this.renderEdit();
}
return this.renderItem();
}
renderEdit = () => {
return (
<input type="text"
ref={(event) =>
(event ? event.selectionStart = this.props.text.length : null)
}
autoFocus={true}
defaultValue={this.props.text}
onBlur={this.finishEdit}
onKeyPress={this.checkEnter}
/>
)
};
renderDelete = () => {
return <button onClick={this.props.onDelete}>x</button>;
};
renderItem = () => {
const onDelete = this.props.onDelete;
return (
<div onClick={this.edit}>
<span>{this.props.text}</span>
{onDelete ? this.renderDelete() : null }
</div>
);
};
edit = () => {
this.setState({
isEditing: true
});
};
checkEnter = (e) => {
if(e.key === 'Enter') {
this.finishEdit(e);
}
};
finishEdit = (e) => {
const value = e.target.value;
if(this.props.onEdit) {
this.props.onEdit(value);
this.setState({
isEditing: false
});
}
};
}
/components/Items.jsx
import React from 'react';
import Item from './Item.jsx';
export default ({items, onEdit, onDelete}) => {
return (
<ul>{items.map(item =>
<li key={item.id}>
<Item
text={item.text}
onEdit={onEdit.bind(null, item.id)}
onDelete={onDelete.bind(null, item.id)}
/>
</li>
)}</ul>
);
}
// UPDATE: http://redux.js.org/docs/basics/UsageWithReact.html
// Is this necessary?
const mapStateToProps = (state) => {
return {
state
}
}
Items = connect(
mapStateToPros
)(Items) // `SyntaxError app/components/Items.jsx: "Items" is read-only`
//////////////////////////////////////
// Also tried it this way.
//////////////////////////////////////
Items = connect()(Items)
export default Items // same error as above.
Tried this as well
export default connect(
state => ({
items: store.items
})
)(Items) // `Uncaught TypeError: Cannot read property 'items' of undefined`
UPDATE:
After many attempts #hedgerh in Gitter pointed out that it should be state.items instead. so the solution was
export default connect(
state => ({
items: state.items
})
)(Items)
credits to #azium as well.
/components/App.jsx
export default class App extends React.Component {
render() {
return (
<div>
<button onClick={this.addItem}>+</button>
<Items />
</div>
);
}
}
What am I missing here in order to implement it correctly? Right now it breaks saying that Uncaught TypeError: Cannot read property 'map' of undefined in Items.jsx. I guess it makes sense since it doesn't seem to be hooked up correctly. This is the first part of the app, where the second will allow an user to create a many lists, and these lists having many items. I will probably have to extract the methods from Item.jsx since the List.jsx will do pretty much the same thing. Thanks
You're missing connect. That's how stuff gets from your store to your components. Read the containers section from the docs http://redux.js.org/docs/basics/UsageWithReact.html
import React from 'react'
import Item from './Item.jsx'
import { connect } from 'react-redux'
let Items = ({items, onEdit, onDelete}) => {
return (
<ul>{items.map(item =>
<li key={item.id}>
<Item
text={item.text}
onEdit={onEdit.bind(null, item.id)}
onDelete={onDelete.bind(null, item.id)}
/>
</li>
})
</ul>
)
}
export default connect(
state => ({
items: state.items
})
)(Items)
Also you seem to be expecting onEdit and onDelete functions passed from a parent but you're not doing that so those functions will be undefined.

Resources