How to pass each component id - reactjs

I want to implement dragging components (beautiful dnd) so that the user can swap them. But for this, each component must have an id, as I understand it. But I do not know how to do it
import React from 'react';
import CardWeather from '../cardWeather/CardWeather';
import WeatherMap from '../cardWeatherMap/WeatherMap';
import Forecast from '../forecast/Forecast';
import WeatherGrapth from '../weatherGraph/WeatherGraph';
import './main.scss';
import { Droppable } from 'react-beautiful-dnd';
const Main = () => {
return (
<>
<Droppable droppableId="main">
{
(provided) => (
<div className="main-container"
ref={provided.innerRef}
{...provided.droppableProps}
>
<CardWeather />
<Forecast/>
<WeatherGrapth/>
<WeatherMap/>
</div>
)
}
</Droppable>
<div className="pr">weather app</div>
</>
)
}
export default Main;

Hi, to do that you also need to use Draggable Component importing from 'react-beautiful-dnd'.
And also if you don't have unique ids for your items you can use 'react-uuid' package to pass through to 'draggableId'. It will create unique ids for you.
And also I am highly recommending to you watch this course about "react-beautiful-dnd". This course was created by who developed "react-beautiful-dnd".
https://egghead.io/courses/beautiful-and-accessible-drag-and-drop-with-react-beautiful-dnd
import React from 'react';
import CardWeather from '../cardWeather/CardWeather';
import WeatherMap from '../cardWeatherMap/WeatherMap';
import Forecast from '../forecast/Forecast';
import WeatherGrapth from '../weatherGraph/WeatherGraph';
import './main.scss';
import { Droppable, Draggable } from 'react-beautiful-dnd';
import uuid from 'react-uuid';
const Main = () => {
return (
<>
<Droppable droppableId="main">
{
(provided) => (
<Draggable
draggableId={uuid()}
index={"element index"}
>
{(provided, snapshot) => {
<div className="main-container"
ref={provided.innerRef}
{...provided.droppableProps}
isDragging={snapshot.isDragging}
>
<CardWeather />
<Forecast />
<WeatherGrapth />
<WeatherMap />
</div>
}}
</Draggable>
)
}
</Droppable>
<div className="pr">weather app</div>
</>
)
}
export default Main;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

If I get this correctly you need to have some kind of id for every component in your case:
<CardWeather />
<Forecast/>
<WeatherGrapth/>
<WeatherMap/>
You can pass the id by props for each component. Example:
Main component:
<CardWeather id="1" />
CardWeather component:
function CardWeather(props){
const id = props.id
...
return(
<div data-id={id}>
...
</div>
)
}
...
And you have to do that for every component you want to drag and drop.

It's best to have also a key prop to each component. So that if I'd changes you will get a rerender.

Related

My Component isn't conditionally rendering properly

I have a simple react page so far where I just have a home component which seems to work fine it is made up from the code I have included what I am trying to do is to render another component the main component when the button that is part of the home component is clicked but it keeps giving me the error and I have no idea what I am doing wrong in this case I have included code for all of my files the main component isn't fully finished right now it was just to test what I am currently doing that I added a paragraph placeholder any help is appreciated thanks
Error: Unknown error
(/node_modules/react-dom/cjs/react-dom.development.js:3994) !The above
error occurred in the component: at Main (exe1.bundle.js:94:3)
at div at App (exe1.bundle.js:31:52) Consider adding an error boundary
to your tree to customize error handling behavior. Visit
https://reactjs.org/link/error-boundaries to learn more about error
boundaries. !Error: Unknown error
Home Component:
import React from "react";
export default function Home(props) {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner">
</div>
<div className="top-corner">
</div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button
className="start-button"
onClick={props.handleClick}
>Start quiz
</button>
</div>
</main>
)
}
Main Component:
import react from "react";
export default function Main() {
return (
<h1>hello </h1>
)
}
App:
import React from "react";
import Main from "./components/Main"
import Home from "./components/Home"
export default function App() {
const [startQuiz, setStartQuiz] = React.useState(false);
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(prevState => !prevState);
}
return (
<div>
{console.log("start", startQuiz)}
{startQuiz ?
<Main />
:
<Home handleClick={clickStart}/> }
}
</div>
)
}
Index:
import React from "react"
import ReactDOM from "react-dom"
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"))
I think you just have a typo here
import react from "react";
should be
import React from "react";
You can try changing your setStartQuiz to just simply negate the current startQuiz value instead of using prevState.
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(!startQuiz);
}
Here's a working example based on your code.
code sandbox
import React, { useState } from "react";
const Main = () => <h1>hello </h1>;
const Home = (props) => {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner"></div>
<div className="top-corner"></div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button className="start-button" onClick={props.handleClick}>
Start quiz
</button>
</div>
</main>
);
};
export default function App() {
const [startQuiz, setStartQuiz] = useState(false);
return (
<div>
{startQuiz && <Main />}
{!startQuiz && <Home handleClick={() => setStartQuiz(true)} />}
</div>
);
}

I want to display Google Adsense on my gatsby.js site. However, it is not showing up

I want to display Google Adsense on my gatsby.js site. However, it is not showing up.
LeftSideSection is called in Layout.js.
I am running it in a local environment.
And I don't have a domain for my site.
I don't register my site's domain in GoogleAdsense and
I have created an Ad unit.
export
[
googleAdsense.js
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return (
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
data-adtest="on"
/>
)
}
LeftSideSection.js
const LeftSideSection = (props) => {
const { title, children } = props;
const path = props.location?.pathname || '';
return (
<section className={styles.container}>
<p>ads</p>
<Adsense path={path} />
</section>
);
};
export default LeftSideSection;
Layout.js
import React from "react";
import Header from "./Header";
import * as styles from "./Layout.module.css";
import 'bootstrap/dist/css/bootstrap.min.css';
import herderImage from '../images/header.png'
import {Navbar} from 'react-bootstrap'
import RightSideSection from "./RightSideSection";
import LeftSideSection from "./LeftSideSection";
import { Link } from "gatsby";
import { useBreakpoint } from 'gatsby-plugin-breakpoints';
import HeaderRss from "./HeaderRss";
const Layout = ({ children }) => {
const breakPoints = useBreakpoint();
return (
breakPoints.pc ?
<>
<Navbar.Brand as={Link} href='/' >
<img src={herderImage} style={{width:`100%`,height:`200px`,}}/>
</Navbar.Brand>
<Header />
<div className={styles.container}>
<div className={styles.LeftSideSection}>
<LeftSideSection />
</div>
<div className={styles.RightSideSection}>
<RightSideSection />
</div>
<div className={styles.mainPane}>
<div className={styles.headerRssContainer}>
<HeaderRss/>
</div>
{children}
</div>
</div>
<footer className={styles.footer}>
© {new Date().getFullYear()},
{`title`}
</footer>
</>:
);
};
export default Layout;
enter image description here
You are not loading the <script> that the console is suggesting. Try using the Helmet component to do something like:
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return <>
<Helmet>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
</Helmet>
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-adtest="on"
data-full-width-responsive="true"
/>
</>
}
I still don't know what's import {Adsense} from './googleAdsense', this line may collide with the naming of the component that you are defining (both are Adsense). If the issue persists, try changing the name.
To make the ads available on localhost, set the data-adtest as on.
In addition, you can try using a React-based solution like the one that react-adsense suggests.
Double-check and remove AdBlocks (or similar).
However, the image of the ad did not show up.
This can be caused by the localhost. Try deploying the site to check it in a real domain.

React how to update array useState on button click

I have seen a hundred videos and read about this, and it still doesn't make sense to me. I'm trying to update an array on a button click but when I log out the items array, it's one behind, meaning it's not reactive and gets added on the next paint. Also, I wrapped my Employee component inside a div only to be able to add an 'onClick' to it. Ideally, I'd like the onClick to be on the Employee component itself, but it doesn't work. Thanks.
import React, {ReactElement, useState } from "react";
import {TextContainer, Text } from "react-md";
import model from '../Models'
import Employee from './Employee/Employee'
import styles from '../home.module.scss'
export default function Home(): ReactElement {
const [items, setItems] = useState<Array<any>>([]);
const addItem = (val:any) => {
setItems([...items, val ])
console.log('items :', items)
}
return (
<div className='center'>
<TextContainer className='center'>
<Text type='headline-4' style={{color: 'white'}}>Employee List</Text>
</TextContainer>
<section className={styles.emp_list}>
{model.map((props, index) =><div key={index} onClick={() => addItem(props.name)}><Employee key={index} name={props.name} role={props.role} markets={props.markets} image={props.image}/></div>)}
</section>
</div>
)}
And my Employee component:
import React from "react";
import {MediaContainer} from "#react-md/media";
import styles from './employee.module.scss'
import { Card, CardContent, CardHeader} from "react-md";
function Employee(props: any) {
return (
<Card className={styles.emp_card}>
<CardHeader>
<div className={styles.emp_text}>
<p key={props.name}>Name: {props.name}</p>
<p key={props.role}>Title: {props.role}</p>
<p key={props.markets}>Markets: {props.markets[0]} {props.markets[1] && <span>and {props.markets[1]}</span>}</p>
</div>
</CardHeader>
<CardContent>
<MediaContainer>
<img key={props.image} src={props.image} alt="employee"/>
</MediaContainer>
</CardContent>
</Card>
)
}
export default Employee;
I don't think the documentation is clear enough on this, but if you want to setState using the previous state, then you should pass a function to useState. For example:
const addItem = (val:any) => {
setItems(prevItems => [...prevItems, val ])
}
https://reactjs.org/docs/hooks-reference.html#functional-updates

how to use react routing to switch between pages

i am currently building a shopping website . i finished the homepage and i have to make routing for other pages
i have 3 main files: App.js, Menuitem.js (which is to execute props), and Homepage.js (which also is used to apply executing props from sections array which includes titles and background images and sections paths)
this is the App js
import React from "react";
import Homepage from './Homepage'
import "./styles.css";
import './Homepage.css'
import {Route, Switch} from "react-router-dom";
const Hatspage=function() {
return(
<div>
<h1>
Hats page
</h1>
</div>
)
}
function App() {
return (
<div>
<Switch>
<Route exact path='/'component={Homepage}/>
<Route path='/hats'component={Hatspage}/>
</Switch>
</div>
);
}
export default App
Menuitem.js
import React from 'react'
import {WithRouter} from 'react'
const Menuitem= function(props){
return(
<div className='card' style={{ backgroundImage: `url(${props.imageUrl})` }} >
<div className='text-frame'>
<h1 className='title'>{props.title}</h1>
<p className='subtitle'>shop now</p>
</div>
</div>
)
}
export default Menuitem
Homepage.js
import React from "react";
import sections from './directory-components';
import Menuitem from "./menu-item-components";
const arrayOne=[sections.slice(0,3)]
const arrayTwo=[sections.slice(3,)]
function extract(item){
return(
<Menuitem
title={item.title} imageUrl={item.imageUrl}/>
)
}
function Homepage(){
return(
<div className='directory-menu'>
<div className='content'>
{sections.slice(0,3).map(extract) }
</div>
<div className='second'>
{sections.slice(3,).map(extract) }
</div>
</div>
)
}
export default Homepage
so i need for example when i click on hats picture i switch to hats page . how to do that
image attached
Thanks in advance
reactjs routing
You can do two different approaches. Both of them will require an extra prop that will be the actual url you want to access when clicking the menu item.
Assuming you modify your section array to look like this:
[{title: 'Your title', imageUrl: 'your-image.jpg', linkUrl: '/hats'}]
And you modify your extract function to add the url value as a prop in the MenuItem component:
function extract(item){
return(
<Menuitem
title={item.title} imageUrl={item.imageUrl} linkUrl={item.linkUrl} />
)
}
You can do this
First one: Using a Link component from react router:
import React from "react";
import { Link } from "react-router-dom";
const Menuitem= function(props){
return(
<Link to={props.linkUrl}>
<div className='card' style={{ backgroundImage: `url(${props.imageUrl})`
}} >
<div className='text-frame'>
<h1 className='title'>{props.title}</h1>
<p className='subtitle'>shop now</p>
</div>
</div>
</Link>
)
}
Now you will have to add extra styling because that will add a regular a tag, but I like this approach because for example you can open the link in a new tab since it is a regular link.
Using the history prop.
import React from "react";
import { useHistory } from "react-router-dom";
const Menuitem= function(props){
const history = useHistory()
const goToPage = () => history.push(props.linkUrl)
return(
<div className='card' style={{ backgroundImage: `url(${props.imageUrl})`
}} onClick={goToPage} >
<div className='text-frame'>
<h1 className='title'>{props.title}</h1>
<p className='subtitle'>shop now</p>
</div>
</div>
)
}
This approach is a basic on click so if you press the component it will go to the selected page, this will work but keep in mind that event bubbling will be harder if you add more on clicks inside the menu item, so please be aware of that.
You should fire an event inside your MenuItem in order to redirect the user
import { useHistory } from 'react-router-dom'
const history = useHistory()
<img onClick={() => history.push('/hats')} />

Parent component that can get different components

I have a <Panel/> component that has to get different changing components.
For example one time- the <Panel/> needs to contain a <Dropdown/> component, a second time a <TextInput/> and in the third time a <Checkbox/>.
How can I make this <Panel/> component to get different components?
The <Panel/> component:
import React from "react";
import { css } from "emotion";
import colors from '../../styles/colors';
import PanelHeader from "./PanelHeader";
export default function Panel({ active, panelHeader}) {
const styles = css({
borderRadius: 4,
backgroundColor: "white",
border: `1px solid ${ active ? colors.blue : colors.grayLight }`,
width: 540,
padding: 32,
});
return (
<div className={styles}>
{panelHeader && <PanelHeader headerType={panelHeader} />}
</div>
);
}
The Panel story:
import React from "react";
import { storiesOf } from "#storybook/react";
import Panel from "../components/Panel";
import colors from '../styles/colors';
import PanelHeader from "../components/Panel/PanelHeader";
storiesOf("Panel", module)
.add("Default", () => (
<Panel></Panel>
))
.add("Active", () => (
<Panel active></Panel>
))
storiesOf("Panel/PanelHeader", module)
.add("Default", () => (
<PanelHeader headerType="Identity document" color={colors.gray}>1</PanelHeader>
))
.add("Active", () => (
<PanelHeader headerType="Identity document" color={colors.blue}>1</PanelHeader>
))
You can change Panel to accept children prop, pass it where you Render <Panel> and pass in the corresponding component.
For example:
// PropType for children is `PropTypes.node`
export default function Panel({ active, panelHeader, children}) {
// ...
return (
<div className={styles}>
{children}
</div>
);
}
// ...
<Panel><Dropdown /></Panel>
// or
<Panel><TextInput /></Panel>
Or, you could pass in a component class/function and render it inside:
export default function Panel({ active, panelHeader, ChildComponent}) {
// ...
return (
<div className={styles}>
{/* This is like any other component,
you can pass in props as usual. */}
{/* It's important for the name to start with an uppercase letter,
otherwise the JSX compiler will turn this in a string! */}
<ChildComponent />
</div>
);
}
// ...
<Panel ChildComponent={Dropdown}></Panel>
// or
<Panel ChildComponent={TextInput}></Panel>
This pattern is called component composition. You can read more in React docs: https://reactjs.org/docs/composition-vs-inheritance.html

Resources