How can I import text file on React? - javascript

I have the following text files in the same directory with my code:
Text1.txt:
This is text1
Text2.txt
This is text2
I want to make a page where when a user clicks a list, each list connects with a text file and the content of text file will be shown in the console. How do I do it?
App.js
import React, { Component } from 'react';
import './Text1.txt';
import './Text2.txt';
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Text Lists</h1>
<div>
<h2 onClick={this.showTitle}><li>Click this to show text1</li></h2>
<h2 onClick={this.showTitle}><li>Click this to show text2</li></h2>
</div>
</div>
);
}
}
export default App;

Assuming you are using webpack in your implementation, you will need to use file-loader to do this.
You can read on how here. It's pretty simple if you have done the same with css or any other style loaders.
module.exports = {
module: {
rules: [
{
test: /\.(txt)$/i,
loader: 'file-loader',
options: {
publicPath: 'assets',
},
},
],
},
};
Once the loader is setup you should be able to import it like you would a module
import textfile from './Text1.txt';

Related

loading css in asynchronously imported javascript using webpack with MiniCssExtractPlugin

i'm working on a webapp that loads it's different pages asynchronously via dynamic imports e.g.:
import {Component, h} from "preact";
import AsyncRoute from "preact-async-route";
import {Layout} from "components/layout";
import {PageLoading} from "components/page-loading";
export class Page extends Component {
render() {
return (
<Layout>
<AsyncRoute
key="doorstation"
path={"/doorstation"}
getComponent={this.getSamplePage}
loading={() => <PageLoading />}
/>
</Layout>
);
}
async getSamplePage(){
const { init, Page } = await import("modules/sample");
init();
return Page;
}
}
and in the actual imported file i do
// modules/sample/page/index.tsx
import {Component, h} from "preact";
import styles from "./styles.css";
export class Page extends Component {... components logic}
// modules/sample/index.tsx
export const init = () => // some initialization logic
export { Page } from "./Page"
Each of those pages has their own css that gets imported on their respective file. What i'm stuck now with is that it puts the resulting css in it's own chunk but when the browser build tries to import said css it just fails with an error like:
GET http://<my-ip>/341.()=%3E%225028a51a47a787d4cc85%22.css net::ERR_ABORTED 404 (Not Found)
Error: Loading CSS chunk 341 failed.
(/341.()=>"5028a51a47a787d4cc85".css)
at o.<computed>.o.<computed>.<computed>.e.push.o.<computed>.d.onerror
on inspection of the import on the console the href of resulting stylesheet tag is actually set to:
link.href = "http://<my-ip>/341.()=%3E%225028a51a47a787d4cc85%22.css"
what i expected was that webpack would resolve those paths on my dynamically imported modules but apparently this isn't the case.
for now my config looks like this:
module: {
rules: [
test: /\.css$/,
use: [
{
loader: args.mode === "production" ? MiniCssExtractPlugin.loader : "style-loader",
},
{
loader: "css-loader",
options: {
sourceMap: args.mode !== "production",
importLoaders: 1,
modules: {
localIdentName:
args.mode === "production"
? "c-[hash:base64:8]"
: "[name]-[local]-[hash:base64:4]",
},
},
},
{
loader: "postcss-loader",
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[hash:8].css",
chunkFilename: "[name].[hash:8].css",
}),
]
by just using the style-loader everything works just fine but this won't give me actual css chunks. I'm not entirely sure where or what to change so webpack will require the actual css chunk files instead of resolving the path with that... what looks like an function expression. I was already looking up the issue but so far it didn't really solve my issue since it usually revolved around undefined values or something.
Did i miss something in this config? is someone able to help?
Thank you in advance.

Storybook not showing styles

I have a dialog component which is using the Primereact dialog internally. When I make a storybook for the same, the custom css for button is being imported as it is imported inside dialog.jsx. But the default css of Primereact dialog is not loading and reflecting in the storybook. Although it is being loaded in my React app.
dialogComp.jsx
import { Dialog } from "primereact/dialog";
const DialogComp = (props) => {
return (
<Dialog
className="dialog-modal"
header={props.header}
visible={true}
>
{props.children}
</Dialog>
);
};
export default DialogModal;
dialog.storybook.js
import React from "react";
import DialogModal from "./dialogComp";
import { addDecorator, addParameters } from "#storybook/react";
import { Store, withState } from "#sambego/storybook-state";
import { store } from "./../../utils/storyStore";
const DialogModalComp = (props) => {
return [
<div>
<DialogModal
header="Dialog Modal"
displayModal={true}
>
Modal content
</DialogModal>
</div>,
];
};
addDecorator(withState());
addParameters({
state: {
store,
},
});
export default {
title: "dialog",
};
export const DialogModalComponent = () => DialogModalComp;
storybook---main.js
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials",
"#storybook/preset-create-react-app"
]
}
Am I missing something in the configuration?
You'll need to import any styles you use in App.js globally in Storybook, by importing them in .storybook/preview.js (create the file if it doesn't already exist).
Every component in React is self contained - your DialogModal component won't get styled because in Storybook it is not being rendered within your App component (where you're importing your styles).
To simulate your app when using Storybook, you import the css in a preview.js file.
Docs:
To control the way stories are rendered and add global decorators and
parameters, create a .storybook/preview.js file. This is loaded in the
Canvas tab, the “preview” iframe that renders your components in
isolation. Use preview.js for global code (such as CSS imports or
JavaScript mocks) that applies to all stories.
TL;DR
import your styles in .storybook/preview.js
import "../src/index.css";
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
If you use storybook and emotion, and if you implement Global styles or Theming, you may add a decorator into the .storybook/preview.js like this:
I'm using Create React App, therefore I'm using jsxImportSource
/** #jsxImportSource #emotion/react */
import { Global } from '#emotion/react'
import { GlobalStyles } from '../src/styles'
const withGlobalProvider = (Story) => (
<>
<Global styles={GlobalStyles} />
<Story />
</>
)
export const decorators = [withGlobalProvider]
You may find more information on: https://storybook.js.org/docs/react/essentials/toolbars-and-globals#global-types-and-the-toolbar-annotation

How to use Webpack to load a static file with a relative path with React?

I'm trying to create a map component in React using the Tangram Library.
I got it working with Webpack alone but it started bugging out when I used react in the mix.
I've tried using various loaders such as a raw loader, a yaml loader and so forth, but none of them have worked thus far.
The map component looks as follows:
// -- Import dependencies --
import React from 'react';
import { Map } from 'react-leaflet';
// -- Import Tangram --
import Tangram from 'tangram';
import yaml from 'js-yaml';
import data from '!!raw-loader!./scene.yaml';
export default class LeafletMap extends React.Component {
componentDidMount() {
const layer = Tangram.leafletLayer({
scene: data
});
layer.addTo(this.map.leafletElement);
}
render() {
return (
<Map center={[40.70532, -74.00976]} zoom={15} ref={(ref) => { this.map = ref }} />
);
}
}
How can I actually load the scene.yaml so that the Tangram library makes use of it ?
In the end it responds with a 404 as the file isn't found.
The solution was, that the static files weren't being copied to the bundle built by webpack.
I solved it by using the CopyPlugin in the webpack config and copying the files to a folder respecting the relative path name, like so:
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: './bundle.js'
},
plugins: [
new CopyPlugin([
{ from: 'src', to: 'src' },
]),
],
};

Why is my CSS not applying to my React components?

Say I'm creating a React app and have some CSS for components. I've added the style-loader and css-loader to my webpack config here:
module.exports = {
mode: 'development',
entry: './client/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-react']
}
}
}, {
test: /\.css$/,
loader: 'style-loader'
}, {
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
output: {
path: __dirname + '/dist',
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist'
},
devtool:"#eval-source-map"
};
I have a simple CSS file just to test on one component:
.list-group-item {
border: 1px solid black;
outline-style: solid;
outline-color: red;
outline-width: medium;
}
In my app I'm applying the classname to a element in my component and importing my CSS
import React, { Component } from 'react'
import { connect } from 'react-redux'
import selectContact from '../actions/action_select_contact'
import { bindActionCreators } from 'redux'
import '../styles.css';
class ContactList extends Component {
renderList() {
return this.props.contacts.map((contact) => {
return (
<li
key={contact.phone}
onClick={() => this.props.selectContact(contact)}
className='list-group-item'>{contact.firstName} {contact.lastName}</li>
);
});
}
render() {
return (
<ul className = 'list-group col-sm-4'>
{this.renderList()}
</ul>
);
}
}
function mapStateToProps(state) {
return {
contacts: state.contacts
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ selectContact: selectContact }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(ContactList)
I'm also importing the CSS file in the same way in the ContactList component itself. The rest of the project is here. I would have expected to see an outline around my comtactsList but there is not. There is no CSS when I inspect the page. Why is this not getting applied?
In a react project created with create-react-app or npx create-react-app, I also had the same issue.
I had imported index.css file in my App Component but my styles were not being applied properly to my React Components.
I even tried directly adding index.css file in my html file in the public folder and using link tag to link to my index.css file (which resides within src folder).
<link rel="stylesheet" href="./../src/index.css">
That also didn't work.
Finally, I read an article about 7 ways to apply CSS into React. One best way was to install node-sass into our project and use index.scss ( import './index.scss') into App Component instead of index.css.
And Hurray!!! My CSS worked fine, All the Media Queries started to work fine.
Below is the code snippet you can try.
import React from "react";
import ReactDom from "react-dom";
import './index.scss';
// --- Data to work with ---
const books = [
{
id: 1,
name: 'The Rudest Book Ever',
author: 'Shwetabh Gangwar',
img: 'https://m.media-amazon.com/images/I/81Rift0ymZL._AC_UY218_.jpg'
},
{
id: 2,
name: 'The Rudest Book Ever',
author: 'Shwetabh Gangwar',
img: 'https://m.media-amazon.com/images/I/81Rift0ymZL._AC_UY218_.jpg'
},
{
id: 3,
name: 'The Rudest Book Ever',
author: 'Shwetabh Gangwar',
img: 'https://m.media-amazon.com/images/I/81Rift0ymZL._AC_UY218_.jpg'
},
{
id: 4,
name: 'The Rudest Book Ever',
author: 'Shwetabh Gangwar',
img: 'https://m.media-amazon.com/images/I/81Rift0ymZL._AC_UY218_.jpg'
},
];
const Book = ({ book }) => {
return (
<div className={"book"}>
<img src={book.img} alt="book image" />
<h3>{book.name}</h3>
<p>{book.author}</p>
</div>
)
};
const Books = () => {
return (
<main className={"books"}>
{
books.map(book => {
return (<Book book={book} key={book.id} />)
})
}
</main>
)
};
// Work a bit fast | one step at a time
const App = () => {
return (
<main>
<h2>Books</h2>
<Books />
</main>
)
}
ReactDom.render(<App />, document.getElementById("root"));
/* --- Mobile First Design --- */
.books{
text-align: center;
};
.book{
border: 1px solid #ccc;
text-align: center;
width: 200px;
padding: 1rem;
background: #001a6e;
color: #fff;
margin:auto;
};
h2{
text-align: center;
}
/* --- Adding Media Queries --- */
#media only screen and (min-width: 900px){
.books,.persons{
display:grid;
grid-template-columns: 1fr 1fr;
}
}
To install node-sass, simple do npm install node-sass --save
Then rename all your .css files with .scss and your project with work properly.
The package.json should have the node-sass dependency added as shown below:
"dependencies": {
"node-sass": "^4.14.1",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react-scripts": "2.1.5"
},
Hope this will help many developers :)
It would be helpful to see your React component as well.
Given this code, you are passing className as a property into the component rather than assigning a class to it:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
render() {
return (
<div>
/** This line specifically **/
<ContactList className="contactList" />
<ContactDetail />
<AddContactModal />
</div>
);
}
}
Inside your component, you would need to use className={this.props.className} on a regular HTML tag inside of your component in order to pass the className through.
You can add your specific css file to index.js directly. (like this import './master.css'
)
According to the react documentation here the className can be applied to all DOM regular element such as <div>, <a>, ...
Does your CSS works with the regular tag <div className='contactList'>hello</div> ?
Styling React Using CSS
I had a problem with applying css file to my react component, which solved by adding a .module.css extension to my css file name. I found the answer here in w3schools

Include pictures in JS bundle

My case is the following :
I create a components library for React. So I have a package (bundled with Rollup) that include some pictures (For now only a GIF picture that is used in a component).
The component that use my picture is like this :
import React from 'react';
import PropTypes from 'prop-types';
import ui_spinner from '../../../assets/ui_progress.gif';
/**
* CircularSpinner
* Add a spinner when the user needs to wait
*/
class CircularSpinner extends React.PureComponent {
static propTypes = {
/** Width of the component */
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Height of the component */
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Style of the component (overload existing properties) */
style: PropTypes.object,
}
static defaultProps = {
width: 128,
height: 128,
style: {},
}
render() {
const { style, width, height } = this.props;
return (
<img src={ui_spinner} width={width} height={height} style={style} alt="ui_progress" aria-busy="true" />
);
}
}
export default CircularSpinner;
When I built it, it's OK.
Now I create a React application with create-react-app and I want to test my components library. To do this, I use npm link (To avoid to push deploy my npm package). My components are OK in my testing application but the picture (the GIF in my CircularSpinner component) is not displayed.
So my question is the following : How to include some assets in a JS bundle with Rollup ? My working approach is correct ?
My Rollup config is the following :
import { uglify } from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'
import url from 'rollup-plugin-url'
const config = {
input: 'src/index.js',
external: ['react'],
output: {
format: 'umd',
name: 'react-components',
globals: {
react: "React"
}
},
plugins: [
babel({
exclude: "node_modules/**"
}),
uglify(),
url(),
]
}
export default config
I build with rollup -c -o dist/index.js.
And the dist folder has the following content :
dist/
assets
92be5c546b4adf43.gif
index.js
My component that use my picture is like this in my testing application :
<img src="92be5c546b4adf43.gif" width="128" height="128" alt="ui_progress" aria-busy="true">
Thanks for your help !
Damien
I found the solution for this issue. This response may help someone :
I update my rollup config to use rollup-plugin-img. I have already used it but my configuration was not correct :
The correct config is the following :
import { uglify } from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'
import image from 'rollup-plugin-img'
const config = {
input: 'src/index.js',
external: ['react'],
output: {
format: 'umd',
name: 'react-components',
globals: {
react: "React"
}
},
plugins: [
babel({
exclude: "node_modules/**"
}),
image({
limit: 100000,
}),
uglify(),
]
}
export default config
My error was that my GIF is a little big and the default limit size is 8192 bytes.
In this case, I have the following error :
Error: Could not load <path of image> (imported by <path of component that use image>): The "path" argument must be of type string. Received type undefined
When I have updated my config to increase the limit, everything is OK

Categories

Resources