I am trying to speed up my application and in order to do this, I am lazy loading some components. One of my functional component loads from a .json file and it would be nice to lazy load it as well, but I am not sure how to do it. My code currently looks like this:
import React from 'react';
import Presentation from "../Presentation";
const data = () => import("../assets/sample.json");
const Finder = (props) => {
const {prop1} = props;
return ( <Presentation data={data} selection={prop1} /> );
};
export default Presentation;
When trying to render the Presentation component, it fails with an error (data undefined). How could I lazy load the json file? Is it possible using the react-loadable library? Thanks!
Related
I have a [...pageId].tsx file in the /pages directory.
In getServerSideProps, the page will check a CMS, and find a list of components to render. I want to load those components serverside, then render them out, then return the page.
Using next/dynamic like below will load the components, but it will not render them serverside. They will only stream in on the client. In other words: the customer will see 'Loading...' first, then the component renders. That's not what I want, also not for SEO.
const getDynamicComponent = (c) => dynamic(() => import(`../../components/${c}`), {
loading: () => <section>Loading...</section>,
ssr: true
});
export default function SomePage({page}) {
// Load dynamic component if necessary
let DynamicComponent = getDynamicComponent(page.reactComponent);
}
return (
<DynamicComponent page={page} />
)
}
How can I achieve serverside rendering using dynamic imports?
I have made a components library for ReactNative using react-native-builder-bob for packaging. With some components like Button, Image, etc is working great, but when I try to import a Text component is failing and showing this error:
View config getter callback for component 'RCTTEXT' must be a function
(receive undefined)
If in the project where I import this component do some change, the view is refreshed and the error dissapears, but every time I run the project for first time this error is shown.
Here is the imported component:
import {Text} from 'react-native';
export const MyText = ({...props}) => <Text {...props} />;
And after, this is the way I import this component in another app:
import { MyText } from 'my-library'
export const Example = () => {
return <MyText>Hello</MyText>
}
I was searching for the error of 'View config getter....' and the only I found is, provocated by importing error, but only happens with this component.
What thing could be provocating this error?
Thanks in advance
Try using your custom text component like this.
import {Text} from 'react-native';
export const MyText = ({children, ...props}) => <Text {...props}>{children}</Text>;
Hope it will solve your problem.
well....finally I found the error. Everything is all great from my library of components, but, apparently, in my component library I have the react-native version 0.68.0 and, in the app where I was importing this components I had a lower version (0.67.3). If I use the same version, it is working!
Trying next with layout pattern:
https://github.com/zeit/next.js/tree/canary/examples/layout-component
And the problem is that Layout component get remounted on every page change. I need to use layout component as a Container so it'll fetch data from server on every mount. How can I prevent layout to get re-mounted? Or am I missing something there?
This helped me for persistent layouts. The author puts together a function that wraps your page components in your Layout component and then passes that fetch function to your _app.js. This way the _app.js is actually the components that renders the Layout but you get to specify which pages use which layout (in case you have multiple layouts).
So you have the flexibility of having multiple layouts throughout your site but those pages that share the same layout will actually share the same layout component and it will not have to be remounted on navigation.
Here is the link to the full article
Persistent Layout Patterns in Next.js
Here are the important code snippets. A page and then _app.js
// /pages/account-settings/basic-information.js
import SiteLayout from '../../components/SiteLayout'
import AccountSettingsLayout from '../../components/AccountSettingsLayout'
const AccountSettingsBasicInformation = () => (
<div>{/* ... */}</div>
)
AccountSettingsBasicInformation.getLayout = page => (
<SiteLayout>
<AccountSettingsLayout>{page}</AccountSettingsLayout>
</SiteLayout>
)
export default AccountSettingsBasicInformation
// /pages/_app.js
import React from 'react'
import App from 'next/app'
class MyApp extends App {
render() {
const { Component, pageProps, router } = this.props
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps}></Component>)
}
}
export default MyApp
If you put your Layout component inside page component it will be re-remounted on page navigation (page switch).
You can wrap your page component with your Layout component inside _app.js, it should prevent it from re-mounting.
Something like this:
// _app.js
import Layout from '../components/Layout';
class MyApp extends App {
static async getInitialProps(appContext) {
const appProps = await App.getInitialProps(appContext);
return {
...appProps,
};
}
render() {
const { Component, pageProps } = this.props;
return (
<Layout>
<Component {...pageProps} />
<Layout />
);
}
}
export default MyApp;
Also, make sure you replace all the to <Link href=""></Link>, notice that only have change the Html tag to link.
I struggled because with this for many days, although I was doing everything else correctly, these <a> tags were the culprit that was causing the _app.js remount on page change
Even though this is the topic Layout being mounted again and again, the root cause of this problem is that you have some data loaded in some child component which is getting fetched again and again.
After some fooling around, I found none of these problem is actually what Next.Js or SWR solves. The question, back to square one, is how to streamline a single copy of data to some child component.
Context
Use context as a example.
Config.js
import { createContext } from 'react'
export default createContext({})
_App.js
import Config from '../Config'
export default function App({ Component, pageProps }) {
return (
<Config.Provider value={{ user: { name: 'John' }}}>
<Component {...pageProps} />
</Config.Provider>
)
}
Avatar.js
import { useContext } from 'react'
import Config from '../Config'
function Avatar() {
const { user } = useContext(Config)
return (
<span>
{user.name}
</span>
)
}
export default Avatar
No matter how you mount and dismount, you won't end up with re-render, as long as the _app doesn't.
Writable
The above example is only dealing with readable. If it's writable, you can try to pass a state into context. setUser will take care the set in consumer.
<Provider value={useState({})} />
const [user, setUser] = useContext(Config)
setUser is "cached" and won't be updated. So we can use this function to reset the user anytime in child consumer.
There're other ways, ex. React Recoil. But more or less you are dealing with a state management system to send a copy (either value or function) to somewhere else without touching other nodes. I'll leave this as an answer, since even we solved Layout issue, this problem won't disappear. And if we solve this problem, we don't need to deal with Layout at all.
I have a component that takes a long time to load, when the user loads my homepage and when there is noting else left for the browser to do, I want to pre-fetch this heavy component in the background so that when the user clicks the link to load it, it's there instantly.
Is there a way to do this eager pre-fetching for later in React?
Code splitting implementation when using mapbox-gl with react-app using React.lazy and Suspense
import React from 'react';
import mapboxgl from 'mapbox-gl';
// IMPORTANT Please include the css required for mapbox-gl in the same file
import 'path-to-vendor-css/_mapboxgl.external.css';
function MyMapbox() {
// your map implementation
}
Now lazy-load the component where you want to use it.
import {lazy, Suspense} from 'react';
const MyMapbox = lazy(() => import('path-to-the-mapbox-component'))
// usage
//fallback prop displays "loading..." content
<Suspense fallback={<div>Loading...</div>}>
<MyMapbox/>
</Suspense>
I have a react application that generates HTML output based on some configuration. Like this:
export const getHtml = (config) => {
const {classes, children} = config
return (<div className={classes.join(' ')}>{children}</div>);
}
Inside the react app I can easily display the resulting DOM objects, but I want to save the HTML code to DB, to display it on a different page (without loading react/parsing the config again)
I could not find a way to convert the JSX object to plain HTML...
Use the renderToStaticMarkup method. As per the documentation:
You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
const htmlString = ReactDOMServer.renderToStaticMarkup(
<div>
...
</div>
);
redux code:
Here is the full code that I had to use in my react/redux application.
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import {Provider} from 'react-redux';
...
class ParentComponent extends React.Component {
...
getHtml(config) {
const {classes, children} = config
return ReactDOMServer.renderToStaticMarkup(
<Provider store={this.context.store}>
<ChildComponent classes={classes}>{children}</ChildComponent>
</Provider>
)
}
}
ParentComponent.contextTypes = { store: React.PropTypes.object };
Notes:
Use ReactDOMServer.renderToStaticMarkup() to get the HTML code
Specify ParentComponent.contextTypes to make this.context.store available
Need to wrap the ChildComponent in a Provider so it has access to the redux store.