I have a question regarding how to correctly use .scss modules(and common css modules) when it comes to use the same .scss module in several components at once.
For instance: if a parent & its children need to access the same exact .scss module, which way is the best to access the module?
Assume I have a .scss module which contains all styles and a component AudioPlayer that has a structure like this:
import audioPlayerModule from './SCSS/AudioPlayer.module.scss';
/*Some code*/
return (
<div className={audioPlayerModule.audio_container}>
<LeftControls/>
<CenterControls />
<RightControls/>
</div>)
The main AudioPlayer component uses the module audioPlayerModule. Then let's say I need this module again inside the child component LeftControls:
import audioPlayerModule from './SCSS/AudioPlayer.module.scss';
const LeftControls = () => {
return (
<div className={audioPlayerModule.left_controls_container}></div>
);
}
Thus I have imported the same .scss module "audioPlayerModule" to parent & each of its children. Is there any better way to do it without using "props.children"?
You can pass className props to your child components
<LeftControl className={audioPlayerModule.left_controls_container}/>
and then spread this props in child
const LeftControls = ({props}) => {
return (
<div {...props}></div>
);
Related
I would like to implement layout-based routing in my pages directory. I am looking for a way to use something similar to the _app.tsx file, but only for the files inside a specific folder.
This would function similarly to the Remix routing style, where there is a folder, such as panel and a file called panel.tsx that wraps the files inside the "panel" folder with a layout.
How can I achieve something similar in the Next.js pages directory?
What I want:
pages/
panel/
index.tsx
dashboard.tsx
panel.tsx
The panel.tsx file will function like a layout in new app directory basically i want to find a way to wrap around files inside a folder just exactly like how Remix does it or the new app directory
What you are talking about is called Per-Page Layouts in Next.js. And it works as follow, as you can read on the doc:
If you need multiple layouts, you can add a property getLayout to your page, allowing you to return a React component for the layout. This allows you to define the layout on a per-page basis. Since we're returning a function, we can have complex nested layouts if desired.
// pages/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return (
/** Your content */
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
The above is for the / page, but the logic is the same for any route. Just adapt your imports and layouts names, and you will be good to go.
I am trying to implement server components in my Next.js app. I'm using scss modules for styling.
A typical component in my project looks like this:
//MyComponent.client.jsx
import s from './MyComponent.module.scss';
export const MyComponent = ({ props }) => {
return <div id={ s.wrapper }>{ props.stuff }</div>
};
When I change this to: MyComponent.server.jsx
Styling ceases to work, and I don't get any errors.
How can I maintain this functionality in a server component?
In my parent component, I'm receiving an object from an API that I later inject an image into as a key/pair value. I then pass that object off to a child component to be rendered, and I have attempted to follow this post to do so:
Load images based on dynamic path in ReactJs
However, despite copying webpack's necessary image import format, I'm still receiving this error.
Error: Cannot find module '../images/test.jpg'
That path can be used directly in the component just fine... but when imported as such... things break.
Here is the code from the child component:
const WorldInfo = (props) => {
return props.world ? (
<div className={props.className}>
<h1>{props.world.map}</h1>
<img src={require(`${props.world.image}`)}/>
</div>
) :
null
}
Thanks for looking friends!
Instead of passing a full path (relative or absolute), pass only the last name (test.jpg). WebPack will detect a dynamic require and will bundle all the files inside the folder, like so: require('../images/' + props.world.image).
I've built a ReactJS component library that I use for multiple projects installed via an NPM package using a sim link. I want to use the context API to pass data from a parent component served from the component library to my base project to be consumed by multiple consumer components also served from the component library. When I try the context is always undefined in my child components.
If I place my consumer component in my provider component within my library it works like a champ but this defeats what I'm trying to achieve. If I export both the provider and the consumer to my base project the consumer doesn't see the provider.
This is from my base project
import { Screen, COD, GenericSocketServer } from 'component-library'
export default class View extends React.PureComponent {
render() {
return (
<Screen className="screen odmb1">
<GenericSocketServer>
<COD />
</GenericSocketServer>
</Screen>
)
}
}
This is my provider code exported from my 'component-library'
import React from 'react';
import MyContext from "./context";
import COD from './../cod';
export default class GenericSocketServer extends React.Component {
render() {
return (
<MyContext.Provider value={{ foo: 'bar' }}>
<COD />
{this.props.children}
</MyContext.Provider>
);
}
}
This is my content code used in 'component-library'
import React from 'react'
const MyContext = React.createContext()
export default MyContext
This is my consumer component exported from 'component-library'
import MyContext from "../GenericSocketServer/context"
class COD extends React.Component {
render() {
return (
<React.Fragment>
<MyContext.Consumer>
{(context) => {
/*
context comes back undefined
I expect { foo: 'bar' }
*/
console.log('context :', context)
return (
<p>This should work</p>
)}}
</MyContext.Consumer>
</React.Fragment>
)
}
}
Context always comes back undefined as if it doesn't see the parent provider. I think I'm ether doing something wrong initializing the context myself or for some reason the two components I'm importing just don't share the same context. Please help!! Not sure if I should give up on this and just use redux.
Maybe you are making multiple instances of the component providing the context. Let's say you have a component Sound, which starts by:
const { Provider, Consumer } = React.createContext();
If you import this library from your main project, the context will be created at the global space. You then use it to render your document tree. But in another component you also imported this library, which had to be resolved during webpack transpilation. It thus has its own copy of the above lines and a context object created in its own space. The problem occurs when you try to use the Consumer, because the Provider was only made by the main project for the first context object, and the second context's provider instance was never instantiated, thus returns undefined.
A solution to the problem is to enforce a single context object, which you can achieve by telling the second component's webpack that the provider-owning library is an external, so when webpack reaches e.g. the "import sound" line, it will not go further and will assume this dependency is resolved at runtime. When runtime comes, it will take it from the same place where the main project is taking it. To do this in webpack, e.g. for above "sound" library, add this to your other component (not main project):
{
...
externals: {
...
'sound': 'sound'
}
...
}
Also in your component package.json:
{
...
peerDependencies: {
"sound": "^1.2.3"
}
}
Apart from Darko's answer, esm and cjs export is also a possible reason for context to fail in a package. If you use the hook in esm and the provider in cjs, you will not get the value for that context.
I recently had a similar issue where I was trying to consume the value of a context inside my library components but using the provider (imported from the package) in the host app.
I managed to solve the issue just by making react and react-dom external and peerDependencies when bundling in rollup.
should your code of consumer be
<React.Fragment>
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
</React.Fragment>
as stated from the official react doc : https://zh-hant.reactjs.org/docs/context.html
when you define
you can use it like
I am giving my component 2 props src and alt so that it could display an image like so:
<img src={require(this.props.src)} alt={this.props.alt} />
Running my app gives me this error
Error: Cannot find module "."
I tried the image URL and it is correct and works, the app just doesn't want to work when I supply require the props.
If you're using webpack, I'm going to assume that you're using the webpack image loader. If that's the case it means that you're importing your images in your component, probably using named imports. In that case you can pass the named import as a prop to either a child component or use it directly on the component where the import lives.
// named import
import landscape from "./img/landscape.jpg";
// child component
import Child from "./components/child";
const Parent = () =>
<div>
<Child src={landscape} />
</div>;
// then the child component could look like this
const Child = (props) =>
<div>
<img src={props.src} />
</div>;
If this is not the case, please give more information regarding how webpack is handling the images in your components.