How to pre-fetch a component for later in React? - javascript

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>

Related

React withRouter and params accessing in class components router v6

Recently i started new project and upgraded for it libraries to newest including react. I encountered first problem when accessing passed params from dynamic route inside class component. In the past in order to do it, one would need to wrap exported class component in withRouter function returned from router. In the documentation they say that this functionality has been removed in v6 and if you need it, it can be recreated manually docs link.
I created with-router.jsx file and pasted their code:
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
next i added it to my class component:
import React, { Component } from 'react';
import withRouter from './with-router';
class Product extends Component {
render() {
return (
<div className="product">...</div>
);
}
}
export default withRouter(Product);
and it does not work, there is following error:
Compiled with problems:
WARNING in ./src/components/product.jsx 67:15-25
export 'default' (imported as 'withRouter') was not found in './with-router' (module has no exports)
so it does not seem like their own code is working, maybe someone has an idea how to make it work? another thing is to consider future implications, functionality deleted without replacement and if you need it - recreate it? why remove if you have to manually add it anyway, does not make sense with react recently.
"react": "^18.2.0"
"react-dom": "^18.2.0"
"react-router-dom": "^6.4.4"
"webpack": "^5.74.0"
"webpack-cli": "^4.10.0"
"webpack-dev-server": "^4.11.1"
As the error points out, it seems you neglected to export your custom withRouter HOC.
Compiled with problems: WARNING in ./src/components/product.jsx
67:15-25 export 'default'* (imported as 'withRouter') was not found in
'./with-router' (module has no exports*)
* Emphasis is mine
Assuming you've shared the complete with-router.jsx file contents, it's missing a default export.
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
export default withRouter; // <-- add default export!
so it does not seem like their own code is working, maybe someone has
an idea how to make it work?
The RRD code is well maintained and tested, I've not run across many blatant issues/bugs with their React hooks.
another thing is to consider future implications, functionality
deleted without replacement and if you need it - recreate it? why
remove if you have to manually add it anyway, does not make sense with
react recently.
I think it does make sense with the direction React is going.
React has made it clear that Function components and React hooks are the future of React (for now) and that Class components are, for all intents and purposes, deprecated, though they are kept around for compatibility reasons. The functionality you describe as being "deleted", i.e. removed, was replaced... by the new React hooks, and the FAQ doc you referenced is made available as a compatibility bridge if you are using current RRDv6 components with older React code. Creating this HOC is trivial, if you need it, but if the main objective is to create React function components that use React hooks then there's no need or desire for RRD to export a withRouter HOC of their own that encourages "deprecated" React component coding patterns.
A good general rule here would be to use your new withRouter component on your older class components, and for any new components you create implement them as React Function components and use the React hooks. If you want you can rewrite/convert older class components to function components, but this is basically a "only if you really need/want to" and not a "don't just convert for the sake of converting" type of thing.

Component Palette Custom Hook

I am fairly new to React and still wrapping my head around custom-hooks. I cam across a code where a custom hook was created to handle the component imports.
useComponentPalette.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
const defaultComponents = {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
export function useComponentPalette(){
return defaultComponents
}
And then in order to use the hook,
const {TodoItem, TodoList, Checkbox } = useComponentPalette()
My Question :- Does this approach provides any advantage over the regular imports in the component ? or this is an anti-pattern ?
How I usually import the components is as follows
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
function App(){
return(
<>
<TodoList/>
</>
)
}
It's not a good idea to use react hooks like this you can get the same result without react hook
// first file name.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
export default {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
//component file
import * as Component form 'first file name';
//<Component.TodoEditor/>
//or
import {TodoEditor} form 'first file name';
The way that I use react-hooks is for making my code more dry and increase it's readability, so react-hooks is not good fit for this kind of usage.
Hi #Sachin,
In my option, React JS use hook to manage reuse stateful logic between components. In other word, Hooks do well to encapsulating state and share logic. If you want to do some stateful logic or condition base logic with these components, then it's fine with that. But if you are using just without condition in the given components. Then, This Is useless for making the custom hook. You can do that without a custom hook in a simpler way.
Here is a simple way to do that:-
In components folder. I create index file, this is the entry point of all my exporting components
In that file. I export all my components, as you can see.
I use that components like this. It much better way. In my option.
import { Header, Footer, Sider } from "./components"
before using react custom hooks, we should be aware of the rationale behind it.
Customs hooks functionality was provided to reuse stateful logic. If logic doesn't require any state, we will use simple functions and if it is about components only there there are different patterns for making code general and scaleable.
So, there is no usage of custom hook in above case at all. For me, I would go with the following code for above scenario:
// components/index.tsx
import {Todo} from './todo'
import {CheckBox} from './components/CheckBox'
export {
Todo,
CheckBox
}
// componentns/todo/index.tsx
import {Editor} from './Editor'
import {Item} from './Item'
import {List} from './List'
const Todo = {
Editor,
Item,
List
}
export default Todo;
and usage will be like
import { Checkbox, Todo } from "components"
...
<Checkbox ... />
<Todo.List ...>
<Todo.Item ... >
</Todo.Editor ... />
</Todo.Item ... >
</Todo.List>
...
P.S Usage can be different based upon the logic of components, just giving an hint how we can patterns to serve our purpose.
Hope it helps.

Latest version of Emotion styled components not applying styles to elements rendered immediately

We have a few cases in our app where #emotion/styled is not rendering the styles for a component. The weird thing is, it is applying a somewhat class name to the component, yet the class has no associated styles, as seen in this image.
You would expect to see a green background for this particular div, but we don't see anything. This is also happening when we render SVG content directly in React and use the CSS fill property in emotion. The logo will sometimes appear all black as the fill is never included in the resulting generated emotion CSS, but other times it is. This later case usually occurs after a rebuild/redeploy of the app loading for the first time in the browser. After a refresh, it shows the correct fill. However, in the first case, it never worked.
In the first case, we initially had some react useEffect code make a BE API call to fetch some data, and we displayed that data in the component. In this case it worked fine, the emotion styles were applied correctly. However I refactored it to take a static value and render immediately (instead of the async BE API call), and now all of a sudden emotion styles are not being applied.
This only appears on staging environments which have a build, not locally which use the <style> tags to hold emotion content. We use the emotion babel plugin to build, but don't do server-side rendering.
This tells me there is something fishy going on with emotion and static/fast rendering at some point in the component tree. It seems that if we apply an async wait to the system, the styles appear, but otherwise they don't.
Any ideas what could be happening? Sorry I can't share any code but literally it is this vs. this:
// Static.tsx
import React from 'react'
import styled from '#emotion/styled'
const Text = styled.div`
background: green;
`
const StaticComponent = () => {
return <Text>static</Text>
}
export default StaticComponent
// Async.tsx
import React, { useEffect, useState } from 'react'
import styled from '#emotion/styled'
const Text = styled.div`
background: green;
`
const AsyncComponent = () => {
const [text, setText] = useState(null)
useEffect(() => {
setTimeout(() => {
setText('async')
}, 1000)
})
return text ? <Text>{text}</Text> : null
}
export default AsyncComponent
Then something like this to render:
import React from 'react'
import ReactDOM from 'react-dom'
import Async from './Async'
import Static from './Static'
ReactDOM.render(
<><Async/><Static/></>,
document.getElementById('root')
)

How to load props asynchronously for functional component in React

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!

loading css/javascript file based on prop

I am working a reactjs file that uses the react-ace library. Currently my code looks like this
import React, { Component } from 'react';
import 'brace/mode/html';
import 'brace/theme/monokai';
import AceEditor from 'react-ace';
class AceHTML extends Component {
render () {
return (
<AceEditor
mode="html"
theme="monokai"
name="Sample"
showPrintMargin={false}
wrapEnabled={true}
value={this.state.value}
editorProps={{
$blockScrolling: true
}} />
);
}
}
However I am trying to figure out a way to make it more generic. So I could say something like <Ace mode="javascript" /> and then in the component would import brace/mode/javascript instead of brace/mode/html
So my question is: What is the best way to load a library instead of using import?
PS: The reason I specifically pointed out that I am using react is because I am using create-react-app to create the application.
import all assets you want to use and you will be able to make changes as you please.
If you don't want to import all assets initially, you can use dynamic imports and load required chunks when a user requests a different editor configuration:
async changeTheme(theme) {
await import("brace/theme/" + theme)
this.setState({ theme });
}
async changeMode(mode) {
await import("brace/mode/" + mode)
this.setState({ mode });
}
live demo:
https://stackblitz.com/edit/react-nzivmp?file=index.js (without dynamic imports since they don't work on stackblitz)
import React from 'react';
import { render } from 'react-dom';
import brace from 'brace';
import AceEditor from 'react-ace';
import 'brace/mode/html';
import 'brace/mode/javascript';
import 'brace/theme/monokai';
import 'brace/theme/github';
function onChange(newValue) {
console.log('change',newValue);
}
// Render editor
export default ({mode, theme}) => (
<AceEditor
mode={mode}
theme={theme}
onChange={onChange}
name="UNIQUE_ID_OF_DIV"
editorProps={{$blockScrolling: true}}
/>
);
Importing libs isn't job for React. Webpack decides what to load to a bundle file. If you want to use any options based on props you'll need to import both anyway.
If there are large files and you don't want to load both of them for your application's user you can fetch them via AJAX request.

Categories