I am trying to preload/prefetch an image so that I don't have to be connected to the internet at the exact moment to display the image. It's for a "you are offline" page in my app.
My app is written in React and I am using webpack for my bundler.
I was reading online that the webpack magic comments feature might be able to do that.
https://medium.com/webpack/link-rel-prefetch-preload-in-webpack-51a52358f84c
It's not working for me.
The image that I am trying to preload/prefetch does not show and there is no <link rel tag added to the DOM.
Checkout the demo repository here:
https://github.com/aubreyquinn/preload-webpack-demo/tree/main
package.json:
"devDependencies": {
"#babel/core": "^7.19.6",
"#babel/preset-env": "^7.19.4",
"#babel/preset-react": "^7.18.6",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"style-loader": "^3.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
You have to use the useState hook to trigger the re-render, The webpack prefetching is working fine but react is not re-rendering since it is unaware of such loading.
import React, { useEffect, useState } from "react";
import Flowers from "../assets/flowers.jpg";
// Home component
const Home = () => {
const [lilies, setLilies] = useState(null);
useEffect(() => {
import(/* webpackPrefetch: true */ "../assets/lilies.jpg").then((res) => {
console.log(res);
setLilies(res.default);
});
}, []);
return (
<>
<div>React Application</div>
<img src={Flowers} height={200} />
<img src={lilies} height={200} />
</>
);
};
export default Home;
Try the above code out, it's working just fine.
Related
EDIT: I believe the reason that I ran into this problem is I didn't use the ionic start command to create my project and because I didn't have the Ionic CDN in my HTML file.
I hope I can explain this issue I'm having in a clean and concise way.
Environment Information
I am currently using Ionic 6 with React 18
And here are my Dependencies:
"dependencies": {
"#ionic/react": "^6.1.2",
"#ionic/react-router": "^6.1.2",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.1.1",
"#testing-library/user-event": "^13.5.0",
"#types/jest": "^27.4.1",
"#types/node": "^16.11.27",
"#types/react": "^18.0.6",
"#types/react-dom": "^18.0.2",
"axios": "^0.26.1",
"bootstrap": "^5.1.3",
"dart-sass": "^1.25.0",
"node": "16.14.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-router": "^5.3.1",
"react-router-dom": "^5.3.1",
"react-scripts": "5.0.1",
"reactstrap": "^9.0.2",
"testcafe-react-selectors": "^4.1.5",
"typescript": "^4.6.3",
"web-vitals": "^2.1.4",
"xlsx": "^0.18.5"
},
"devDependencies": {
"#types/jest": "^27.4.1",
"#types/node": "17.0.24",
"#types/react": "^18.0.5",
"#types/react-dom": "^18.0.1",
"#types/react-router": "^5.1.18",
"#types/react-router-dom": "^5.3.3",
"#typescript-eslint/eslint-plugin": "^5.19.0",
"#typescript-eslint/parser": "^5.19.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1",
"prettier": "^2.6.2",
"react-scripts": "^5.0.1",
"start-server-and-test": "^1.14.0",
"testcafe": "^1.18.6",
"typescript": "4.6.3",
"typescript-plugin-css-modules": "^3.4.0"
},
Goal
I want to be able to have an Ionic React multi-page application. Obviously it will still be a SPA and not actually have different pages but I want to utilize Ionic's IonPage component which creates a new React View that can be navigated to.
Expected Results
I've stripped much of my project to just bare bones components that I want to be able to use to create a side navigation and be able to navigate to each page and see the contents. Currently I'm just trying to get the ability to see everything from a React Component wrapped in IonPage. This is my App.tsx page:
App.tsx
import { IonApp, IonRouterOutlet, setupIonicReact } from '#ionic/react';
import { IonReactRouter } from '#ionic/react-router';
import React from 'react';
import { Route } from 'react-router';
import Home from './components/Home';
import './custom.css';
setupIonicReact({
mode: 'md',
});
function App() {
return (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route path="/" component={Home} exact={true} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
}
export default App;
I've tried a variety of layouts for my Home.tsx file. Currently this is what is inside
First situation
Home.tsx Current Version
import { IonContent, IonHeader, IonPage } from '#ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>Example</IonHeader>
<IonContent fullscreen>
<h1>Test</h1>
</IonContent>
</IonPage>
);
};
export default Home;
With this setup, the Example Header text shows and is styled like a header correctly. However, the Content Text doesn't show up at all on this. I've determined the reason why it doesn't show up is because the ion-content element/component's height is set to 0. This is not expected. We don't have any css in our project targeting ion-content elements.
Second situation
import { IonContent, IonPage } from '#ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonPage>
<IonContent fullscreen>
<h1>Test</h1>
</IonContent>
</IonPage>
);
};
export default Home;
In this situation I expect the elements inside of the IonContent Component to be rendered. I originally didn't have the 'fullscreen' attribute but added it recently to test if it was different. It didn't have an affect. What the result is is a completely blank page with the ion-page having width of 0 as well as the ion-content having a width of 0. If I set the widths of the ion-page manually it appears the ion-content's width and height update as well and it shows the content I was looing for.
Third Situation
import { IonContent } from '#ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonContent fullscreen>
<h1>Test</h1>
</IonContent>
);
};
export default Home;
In this situation I've removed the IonPage element from the page. Surprisingly it appears that the content is displayed in this situation even though I've seen online that the IonRouter need to find an element with IonPage.
What I want to achieve:
I want to be able to have a react component with IonPage, IonHeader, and IonContent and have all elements inside of these render on the page when navigated to it.
What I want to know
What is causing the IonPage to behave strangely by having 0 height at some points. Why does the Content not show when wrapped around an IonPage but an IonHeader wrapped around an IonPage does show.
No Error Messages Available
Additional Notes
I also attempted to create a new IonicProject with react 17 instead of 18 as I thought it was a support issue, but it appears with the same full code with IonPage, IonContent, and IonHeader the content was not displaying. Thank you for your time!
I basically created a sidenav template from ionic start and determined all of the differences between the two projects.
I eventually determined that there are additional css import statements that I didn't realize I needed to add to my App.tsx in order for the IonApp,IonHeader,IonContent to work correctly.
These are the imports I found from the template project:
/* Core CSS required for Ionic components to work properly */
import "#ionic/react/css/core.css";
/* Basic CSS for apps built with Ionic */
import "#ionic/react/css/normalize.css";
import "#ionic/react/css/structure.css";
import "#ionic/react/css/typography.css";
/* Optional CSS utils that can be commented out */
import "#ionic/react/css/padding.css";
import "#ionic/react/css/float-elements.css";
import "#ionic/react/css/text-alignment.css";
import "#ionic/react/css/text-transformation.css";
import "#ionic/react/css/flex-utils.css";
import "#ionic/react/css/display.css";
/* Theme variables */
import "./theme/variables.css";
The theme variables are option and if there isn't a variables.css file in the theme folder it will give an error.
However after adding these import statements all of the content on the page renders.
I'm attempted to develop a new feature for my blog, that is a Markdown editor for writing articles.
I chosed #tailwindcss/typography and markdown-it to do that, so this is my whole dependencies:
package.json
{
"dependencies": {
"firebase": "^9.0.0-beta.7",
"markdown-it": "^12.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0"
},
"devDependencies": {
"#babel/core": "^7.15.0",
"#babel/preset-env": "^7.15.0",
"#babel/preset-react": "^7.14.5",
"#tailwindcss/typography": "^0.4.1",
"autoprefixer": "^10.3.2",
"babel-loader": "^8.2.2",
"css-loader": "^6.2.0",
"dotenv-webpack": "^7.0.3",
"html-webpack-plugin": "^5.3.2",
"postcss": "^8.3.6",
"postcss-cli": "^8.3.1",
"postcss-loader": "^6.1.1",
"style-loader": "^3.2.1",
"tailwindcss": "^2.2.7",
"webpack": "^5.51.1",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.0.0"
}
}
Below code is the component for this feature, including a editing area and a preview area. However, it didn't work.
When I run this code, it is rendered out like this, without typographing the <h1> tag.
However, if I repalce md.render(markdown) with <h1>hello</h1>(the markdown-it's rendering result), it seems "work", looking like this.
Editor.jsx
import React, { useState } from "react";
const md = require("markdown-it")('commonmark');
const Editor = () => {
const [markdown, setMarkdown] = useState("# hello");
const onTextChange = (e) => {
setMarkdown(e.target.value);
}
return (
<div>
<form>
<textarea onChange={(e) => onTextChange(e)}>
{markdown}
</textarea>
</form>
<div id="preview" className="prose">
{md.render(markdown)} {/* <h1>hello</h1> */}
</div>
</div>
)
}
export default Editor;
Why these things happened? and how can I make it run with expections?
use react-markdown instead of markdown-it
here is an example:
import ReactMarkdown from "react-markdown";
<div className="prose">
<ReactMarkdown>{markdown}</ReactMarkdown>
</div>
it will render the provided content as DOM in the page, and Tailwind/typography perfectly styles those elements.
I am trying to use the material UI snackbar to show pop up errors in my react application.
I am using a container view. In that view, it does some stuff and errors can be thrown. If it does get an error, I want to render my custom snackbar component.
This is my ErrorPopup component:
import React from 'react';
import { Snackbar } from '#material-ui/core';
import MuiAlert, { AlertProps } from '#material-ui/lab/Alert';
function Alert(props: AlertProps) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
interface ErrorProps {
message: string;
}
export default function ErrorPopup(props: ErrorProps) {
const [open, setOpen] = React.useState(true);
const handleClose = () => {
setOpen(false);
};
return (
<div>
{props.message !== '' ? (
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} color="error">
{props.message}
</Alert>
</Snackbar>
) : (
''
)}
</div>
);
}
In my main view, I call this component like so:
<ErrorPopup message={this.state.errors} />
What seems to happen is I get errors that seem to me to indicate something about the WithStyles + typescript issue crops up, but I am out of my depth to fully understand what is going on. I just expected it to work as all my material UI stuff has worked up until now.
I have tried a couple of quick cut n paste run n gun type fixes off the net (as you do), but I clearly don't know what exactly is going on, so I need to at least start there.
Here is a screen grab:
With styles errors perhaps?
First off, is this approach to showing the errors ok?
Secondly, can anyone point me in the right direction here?
Frustratingly, I just ran an npm update on my project, and things started to work.
For anyones reference, my dependencies in package.json
"dependencies": {
"#material-ui/core": "^4.8.3",
"#material-ui/icons": "^4.5.1",
"#material-ui/lab": "^4.0.0-alpha.39",
"#types/pouchdb": "^6.4.0",
"#types/react-router-dom": "^5.1.3",
"clsx": "^1.0.4",
"highcharts": "^7.2.1",
"highcharts-react-official": "^2.2.2",
"pouchdb": "^7.1.1",
"pouchdb-find": "^7.1.1",
"pubnub": "^4.27.3",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",
"react-scripts": "^3.3.0",
"request": "^2.88.0",
"typescript": "^3.7.4"
},
Whilst this solves my original problem getting it working, is this the right approach?
Cheers
The issue is with the reactstrap cards: https://reactstrap.github.io/components/card/
Using reactstrap components like Card, etc is not working.
Component: Version I
import React, { Component } from 'react';
import { Card, Button, CardImg, CardTitle, CardText, CardDeck, CardSubtitle, CardBody } from 'reactstrap';
class MoviesIndex extends Component {
render() {
return (
<CardDeck>
<Card>
<CardImg top width="100%" src="" alt="Movie Poster" />
</Card>
</CardDeck>
);
}
}
export default MoviesIndex;
Output: *It works fine without any errors.
But when I try to use the rest of the components from reactstrap. It throws errors on console.
Component: Version II
import React, { Component } from 'react';
import { Card, Button, CardImg, CardTitle, CardText, CardDeck, CardSubtitle, CardBody } from 'reactstrap';
class MoviesIndex extends Component {
render() {
return (
<CardDeck>
<Card>
<CardImg top width="100%" src="" alt="Movie Poster" />
<CardBody>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle</CardSubtitle>
<CardText>This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</CardText>
<Button>Button</Button>
</CardBody>
</Card>
</CardDeck>
);
}
}
export default MoviesIndex;
Output:
package.json
{
"name": "client",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js",
"test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive ./test",
"test:watch": "npm run test -- --watch"
},
"devDependencies": {
"babel-core": "^6.2.1",
"babel-loader": "^6.2.0",
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.1.18",
"chai": "^3.5.0",
"chai-jquery": "^2.0.0",
"jquery": "^2.2.1",
"jsdom": "^8.1.0",
"mocha": "^2.4.5",
"react-addons-test-utils": "^0.14.7",
"webpack": "^1.12.9",
"webpack-dev-server": "^1.14.0"
},
"dependencies": {
"axios": "^0.17.1",
"babel-preset-stage-1": "^6.1.18",
"lodash": "^3.10.1",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"react-transition-group": "^2.2.1",
"reactstrap": "^4.8.0",
"redux": "^3.7.2",
"redux-promise": "^0.5.3"
}
}
I am not able to debug this issue. Please help! TIA.
The components such as CardBody, etc are not available in v4.8.0.
Upgrading to latest release (reactstrap v5.0.0-alpha.4) resolves this issue!
npm install --save reactstrap#5.0.0-alpha.4
Refer to the issue that I created on reactstrap#github for more details:
https://github.com/reactstrap/reactstrap/issues/730
This looks like a typo here:
renderMovies() {
return _.map(this.props.movies, movie => {
Missing )
Try
_.map(this.props.movies, movie) => {
If that doesn't do it, put console.log() after everything to see where it becomes undefined.
This type of error usually results from something not being exported correctly or something being null/undefined due to data missing, etc.
This is a good opportunity for me to recommend using ES Lint, so you can gain extra help 24/7 from the passive display of errors. Check it out if you aren't using it. It's absolutely worth looking into and using.
I won't recommend any specific linting configs in here. That is out of scope of this help. ES Lint will underline code errors such as the missing ) with a red underline, so you will experience less of this kind of thing :)
I'm playing around with redux, I'm and started getting this error, can't resolve it, I was hoping it has any meaning, but can't seem to find any information.. Can anyone explain the reason this may show? Thanks..
Code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'react-redux';
import { searchForBeers } from '../../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: ''}
this.onFieldChange = this.onFieldChange.bind(this);
this.onClickSearch = this.onClickSearch.bind(this);
}
onFieldChange(event) {
this.setState({ term: event.target.value })
console.log(this.state)
}
onClickSearch() {
console.log(this.state)
this.props.searchForBeers(this.state.term)
}
render() {
return (
<div className="col-lg-6" style={{top:20 , width:'70%'}}>
<div className="input-group">
<span className="input-group-btn">
<button onClick={this.onClickSearch} className="btn btn-secondary" type="button">Go!</button>
</span>
<input type="text" className="form-control" placeholder="Search for..." onChange={this.onFieldChange} />
</div>
</div>
)
}
}
//Container functions
function mapDispatchToProps(dispatch) {
return bindActionCreators({ searchForBeers }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
Package json:
{
"name": "redux-simple-starter",
"version": "1.0.0",
"description": "Simple starter package for Redux with React and Babel support",
"main": "index.js",
"repository": "git#github.com:StephenGrider/ReduxSimpleStarter.git",
"scripts": {
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.2.1",
"babel-loader": "^6.2.0",
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.1.18",
"chai": "^3.5.0",
"chai-jquery": "^2.0.0",
"css-loader": "^0.25.0",
"jquery": "^2.2.1",
"jsdom": "^8.1.0",
"mocha": "^2.4.5",
"node-sass": "^3.10.0",
"react-addons-test-utils": "^0.14.7",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.14.0"
},
"dependencies": {
"axios": "^0.13.1",
"babel-preset-stage-1": "^6.1.18",
"lodash": "^3.10.1",
"material-ui": "^0.15.4",
"raw-loader": "^0.5.1",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-redux": "^4.4.5",
"react-router": "^2.0.1",
"redux": "^3.5.2",
"redux-promise": "^0.5.0",
"redux-simple-promise": "^2.0.2"
}
}
It's the redux module that provides the bindActionCreators function so the correct way to import it would be
import { bindActionCreators } from 'redux';
instead of importing it from react-redux.
There is a page with examples in the docs over at their API documentation site.
The error you're seeing simply looks funky because of the way babel transpiles ES2015 modules but it's not actually React or Redux that's throwing it.