How do I set unique background images for react router components? - javascript

I'd like set to different background images for my 'Home' and 'About' components within the react project I'm building. I gave the 'Home' and 'About' components their own stylesheets (styles.css and about.css, respectively), then added a background-image: url() for each, but they both ended up with the 'Home' background.
Any suggestions on how to have different backgrounds for your components, when using react router?
Code as follows:
Home.jsx
import React from 'react'
import './styles.css'
import hashi_logo_2 from './Photos/hashi_logo_2.png'
import {Link} from 'react-router-dom'
function Home() {
return (
<div className = 'home'>
<nav className = 'nav'>
<ul>
<Link to = '/about' style={{ textDecoration: 'none' }} >
<li className='list'>About</li>
</Link>
<li className='list'>Food</li>
<li className='list'>Events</li>
<li className='list'>News</li>
<Link to ='/shop' style={{ textDecoration: 'none' }} >
<li className='list'>Shop</li>
</Link>
<li className='list'>Contact</li>
<li className='list'>Blog</li>
</ul>
</nav>
<main>
<div class='main__image'>
<img src= {hashi_logo_2}/>
</div>
</main>
</div>
)
}
export default Home
styles.css (styling for 'Home')
html * {
box-sizing: border-box;
font-family: 'Permanent Marker', cursive;
}
body {
margin: 0;
padding:0;
background-image: url('./Photos/hashi_pic_blurred_2.jpg');
background-repeat: no-repeat;
background-size: cover;
backdrop-filter: brightness(100%);
}
/* Navigation */
.nav {
background-color:#8b0000;
margin:0;
padding: 15px 0;
opacity: 0.75;
position: fixed;
width:100%;
}
ul {
display:flex;
list-style: none;
flex-direction: row;
justify-content: space-around;
font-size: 20px;
}
.list {
list-style: none;
text-decoration: none;
color: white;
font-size: 25px;
}
.list:hover{
background-color: black;
}
/* Logo */
main {
text-align: center;
padding-top: 130px;
padding-top:180px;
}
img {
max-width: 40%;
height: auto;
}
About.jsx
import React from 'react'
import './about.css'
function About() {
return(
<div className = 'about'>
<p>
Hashigo Zake takes the provision of fine beer to new levels.
<br/>
<br/>
Seven days a week, 362 days a year, we serve the best that New Zealand's booming craft brewing industry has to offer.
We are also building the best range of imported beer that New Zealand has seen.
<br/>
We deal directly with breweries in Australia, Japan and the US and import many of the best beers in the Pacific rim.
<br/>
We also have access to some of the best beers coming from Europe.
<br/>
<br/>
We open at midday every day.
<br/>
Our location is 25 Taranaki St, Te Aro, Wellington, New Zealand.
</p>
<h2>"And he dreamed, and behold a ladder set up on the earth, and the top of it reached to heaven."</h2>
</div>
)
}
export default About
about.css
.about {
height:100%;
background-image: url('./Photos/hashi_taps.jpg');
}
p {
margin-top: 50px;
color: white;
text-align: center;
font-size: 30px;
/* background-color: rgb(139,0,0, 0.75); */
font-family: 'Open Sans', sans-serif;
padding-left: 50px;
padding-right: 20px;
transform: translateY(20%);
font-weight: bold;
}
h2 {
color: white;
text-align: center;
font-size: 40px;
padding-left: 20px;
padding-right: 20px;
margin-top: 400px;
transform: translateY(-450%);
}
import React from 'react';
import Home from './Home'
import About from './About'
import Shop from './Shop'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
function App() {
return (
<Router>
<div>
<Switch>
<Route path ='/' exact component = {Home}/>
<Route path = '/about' component = {About}/>
<Route path = '/shop' component = {Shop}/>
</Switch>
</div>
</Router>
)
}
export default App;

Related

How to use a component in only one router link

So I have a SPA with multiple routerlinks linking to multiple vue components. I am trying to link a component with props to only one of those "pages". How should I go about doing that?
Thanks in advance.
This is my main vue page where I connect all my routerlinks together.
<script>
import Footer from "./components/Footer.vue";
import Counter from "./components/Counter.vue";
export default {
components: {
Footer,
Counter,
},
};
</script>
<template>
<header class="Header">Welcome to my app</header>
<nav>
<RouterLink
style="text-decoration: none; color: inherit; padding-right: 20px"
to="/"
>
Home
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/about"
>
About
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Dice"
>
Dice
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/FAQ"
>
FAQ
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Calculator"
>
Calculator
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Clock"
>
Clock
</RouterLink>
<RouterLink
style="text-decoration: none; color: inherit; padding-left: 20px"
to="/Counters"
>
Counters
</RouterLink>
</nav>
<main>
<RouterView></RouterView>
</main>
<Footer :copyrightYear="2022"></Footer>
</template>
<style scoped>
nav {
background-color: rgb(63, 63, 63);
}
.Header {
color: rgb(0, 0, 66);
text-align: center;
font-size: 50px;
}
nav {
text-align: center;
font-size: 30px;
}
</style>
And I would like to add a component to the 'Counters' page, something like this:
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
the component looks something like this:
<script>
export default {
props: {
startValue: Number,
incValue: Number,
},
methods: {
increment(a, b) {
a = a + b;
console.log(a);
return a;
},
},
};
</script>
<template>
<button #click="increment(startValue, incValue)">
{{ startValue }}
</button>
</template>
<style scoped>
button {
font-size: 20px;
}
</style>
I would like to add this component to my Counters.vue page:
<script>
export default {
components: {},
};
</script>
<template>
<div class="page">
<h1>Let's count!</h1>
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
</div>
</template>
<style scoped>
.page {
background-color: rgb(251, 255, 0);
text-align: center;
}
button {
font-size: 20px;
padding: 1px;
margin: 10px;
}
</style>
but adding the 'import' or 'components:' lines to the 'Counters.vue' page completely bombs the site. yet it does work fine on the main vue file. How do I link the component to Counters.vue successfully?
You have to import your component directly in the page you are using it and not in the App.vue
CounterView.vue
<script>
import Counter from "./components/Counter.vue";
export default {
components: {
Counter,
},
};
</script>
<template>
<div class="page">
<h1>Let's count!</h1>
<Counter :startValue="0" :incValue="1"></Counter>
<Counter :startValue="45" :incValue="5"></Counter>
<Counter :startValue="33" :incValue="10"></Counter>
</div>
</template>
<style scoped>
.page {
background-color: rgb(251, 255, 0);
text-align: center;
}
button {
font-size: 20px;
padding: 1px;
margin: 10px;
}
</style>
Also I suggest you to have a different name between your component and your page to avoid conflict
e.g:
Counter.vue for the component
CounterView.vue for the page

Footer doesn't stay in place (React-Gatsby)

Why my damn footer won't stay at the bottom of the page?
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
import React from 'react'
import {Link} from 'gatsby'
import {FaFacebook, FaTwitter, FaInstagram} from 'react-icons/fa'
export default function Footer() {
return (
<div id="footer" className="footer">
<div className="footer-middle">
<ul>
<li><Link className="footer-link" to="/">Home</Link></li>
<li><Link className="footer-link" to="/guides">Guides</Link></li>
<li><Link className="footer-link" to="/about">About</Link></li>
</ul>
<div className="footer-bottom">
<ul className="footer-ul">
<li><Link to="//" ><FaFacebook className="footer-dot" /></Link></li>
<li><Link to="//"><FaTwitter className="footer-dot" /></Link></li>
<li><Link to="//"><FaInstagram className="footer-dot"/></Link></li>
</ul>
<p>Build with <Link style={{ textDecoration: "none", color: "#663399" }} to="https://www.gatsbyjs.com/">Gatsby</Link>.</p>
<p>©{new Date().getFullYear()} <Link className="footer-link" to="/about">blablabla</Link> - All Rights Reserved</p>
</div>
</div>
</div>
)
}
/*MAIN CONT*/
.main-cont {
max-width: 1344px;
margin: 0 auto;
display: grid;
height: 100vh;
grid-template-columns: 4.5fr 1.5fr;
grid-template-rows: 1fr 1fr;
gap: 1rem;
grid-template-areas:
"main-post test-ads"
"main-post test-hottopic";
padding-top: 40px;
}
#media only screen and (max-width: 800px) {
.main-cont {
grid-template-columns: 1fr;
grid-template-rows: 2fr 1fr 1fr;
grid-template-areas:
"main-post"
"test-ads"
"test-hottopic";
padding-right: 10px;
padding-left: 10px;
}
}
.main-post {
grid-area: main-post;
}
.test-ads {
grid-area: test-ads;
border: 1px solid greenyellow;
text-align: center;
}
.test-hottopic {
grid-area: test-hottopic;
border: 1px solid red;
text-align: center;
}
/*FOOTER*/
.footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
background: var(--bgGray);
margin: 0;
padding-bottom: 20px;
}
.footer-middle {
color: var(--mainWithe);
}
.footer-middle ul {
list-style: none;
color: var(--mainWhite);
padding: 0rem 2px;
}
.footer-middle li {
font-size: 1.2rem;
display: inline;
margin-right: 1.5rem;
}
.footer-bottom {
padding-top: 0.5rem;
padding-bottom: 2rem;
}
.footer-link {
color: var(--offWhite);
text-decoration: none;
}
.footer-link:hover {
color: var(--mainOrange);
}
.footer-ul {
list-style: none;
display: inline;
}
.footer-dot {
color: var(--offWhite);
height: 27px;
width: 27px;
}
.footer-dot:hover {
transition: var(--mainTransition);
color: var(--mainOrange);
}
The footer seems to stay at the bottom of the screen always, but never at the end of the page. I don't know why, this problem starts when I added the grid to the .main-cont container, because I need a grid nested into the body.
Anyone has a solution?
With Gatsby, you should struck the brain a little bit, since it's not that easy to access the wrappers of the content, but of course, it doable.
Taking your <Layout> as an example:
import React from "react"
import Navbar from "./navbar"
import Footer from "./footer"
import Sidebar from "./sidebar"
import "./layoutplus.css"
const Layout = ({ children }) => {
return (
<>
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</>
)
}
export default Layout
Using the previous structure, you can't access the wrapper of your components because Gatsby wraps it between an unreachable <div> with an empty class. However, what you can do is to wrap it again within a known class element, such as:
const Layout = ({ children }) => {
return (
<section className="site-wrapper">
<Navbar />
<div className="main-cont">
<main id="main-post" className="main-post">{children}</main>
<Sidebar id="sidebar" className="sidebar"/>
</div>
<Footer />
</section>
)
}
Given that site-wrapper class you can add the following CSS:
.site-wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex-grow: 1;
}
Basically, you are telling the wrapper (site-wrapper) to expand until filling the viewport (100vh). Since your main tag (change it to the desired class if needed) can grow free (flex-grow: 1) so your footer will be always at the bottom of the page because it's pushed by the rest of the flexbox column.
Flexbox has better acceptance/fallback within old browsers than grid has, but you can achieve it either way, the idea is always to push (or let the main grow) the footer at the bottom without depending on the content above, using some minmax should do the trick using a grid-based approach.

TypeError: Cannot read property 'map' of undefined - React app - useContext and useReducer issue

I am using react for making an app project using contextHook and reducerHook but getting:
TypeError: Cannot read property 'map' of undefined
The same code was working a few days back, but now it's giving that error. I've wasted so many hours trying to finding answers on the internet, but I couldn't get any help... Here are pictures of the error and my code as well:
Complete code on Github repo
Error Pic 1
Error Pic 2
Error Pic 3
//App.js
import React from 'react';
import './App.css';
import Header from './Header';
import Balance from './Balance';
import AccSummary from './AccSummary';
import TransactionHistory from './Transactionhistory';
import AddTransaction from './AddTransaction';
function App() {
return (
<div className='container'>
<Header />
<Balance />
<AccSummary />
<TransactionHistory />
<AddTransaction />
</div>
);
}
export default App;
//Transaction.js
import React from 'react';
export const Transaction = ({transObj}) => {
return (
<li>
<span>{transObj.description}</span>
<span> {transObj.amount} </span>
</li>
)
}
//TransactionHistory.js
import React, { useContext } from 'react';
import { TransactionContext } from './TransContext';
import { Transaction } from './Transaction';
function TransactionHistory() {
let {transactions} = useContext(TransactionContext);
return (
<div>
<h2> History </h2>
<hr />
<ul className='transaction-list'>
{transactions.map(transObj => (
<Transaction key={transactions.id} transactions = {transactions} />
))}
//Add Transaction.js
import React from 'react';
function AddTransaction() {
return (
<div>
<h2 className='AddTrans'> <br /> Add New Transaction</h2>
<hr />
<form className = 'transaction-form'>
<label>
Enter Description <br />
<input type='text'
placeholder='Enter Detail of Transaction' className='color'/> <br />
</label>
<label>
Enter Amount <br />
<input type='Number'
placeholder='Enter Transaction Amount'/>
</label>
<br />
<input className='button' type="submit" value="Add Transaction"/>
</form>
</div>
);
}
export default AddTransaction;
//TransContezt.js
import { createContext } from "react";
const initialTransaction = [
{amount: 500, description: 'Cash'},
{amount: -200, description: 'Bill'}
]
export const TransactionContext = createContext(initialTransaction);
//App.css
.container {
width: 350px;
min-height: 700px;
margin: 0 auto ;
background-color:white;
box-shadow: 0 0 10px gray;
margin-top: 50px;
padding: 10px 50px;
font-family: "Times New Roman", Times, serif;
background-image: url("1.png"), url("2.png"), url("3.png"), url("4.png");
background-position: left top, left top, left top, left top ;
background-repeat: repeat-x;
background-size: 100% 20%, 100% 55%, 100% 75%, 100% 100%;
}
.text-centre{
text-align: center;
justify-content: space-between;
background-color: #98DBC6;
border-radius: 5px;
display: grid;
justify-content: space-around;
}
.accsumm{
display: flex;
justify-content: space-around ;
background-color: #5BC8AC;
box-shadow: 0 0 10px gray;
border: thin;
font-family: Arial, Helvetica, sans-serif;
border-radius: 5px;
}
.AddTrans{
margin: 10px 0 0;
}
.transaction-form input{
width: 97%;
margin: 10px 0;
padding: 15px 5px;
border-radius: 5px;
color: white;
}
.color{
color: white;
}
.transaction-list{
margin: 0;
padding: 0;
}
.transaction-list > li{
display: flex;
justify-content: space-between;
box-shadow: 0 0 10px gray;
padding: 10px 5px;
background-color: honeydew;
margin: 5px 0;
border-radius: 5px;
}
.button {
width: 100%;
display: flex;
justify-content: space-around;
box-shadow: 0 0 10px gray;
padding: 10px 10px;
background-color: rgb(138, 179, 255);
margin: 10px 0;
border-radius: 5px;
font-size: larger;
font-weight: bolder;
align-self: center;
}
Tr
For the TransactionHistory component:
The default context value is an array but you destructure it like an object.
In the mapping function, you are passing the original array as a prop instead of the element.
Here is an updated version:
function TransactionHistory() {
const transactions = useContext(TransactionContext);
return (
<div>
<h2> History </h2>
<hr />
<ul className="transaction-list">
{transactions.map((transObj, index) => (
<Transaction key={index} transaction={transObj} />
))}
</ul>
</div>
);
}
Then, in the Transaction component, it is expecting transObj prop but its parent passes in transaction prop. So you might fix it as well:
import React from "react";
const Transaction = ({ transObj }) => {
return (
<li>
<span>{transObj.description}</span>
<span> {transObj.amount} </span>
</li>
);
};

Create yellow div above the link if page address matches the link

I have a navigation bar with a unordered list and multiple items that contains links for the individual pages.
I want a yellow box to appear ontop of the link if i'm on that current page. I made the yellow boxes as you can see and i'm trying to think of the best approach for making the box appear on the concurrent page, any ideas?
Part i'm talking about:
const linkStyle = css`
text-decoration: none;
font-family: "Montserrat";
position: relative;
font-weight: 300;
font-style: normal;
color: ${theme.colors.text};
&::after {
background-color: ${theme.colors.primary};
width: 150%;
height: 40px;
content: "";
position: absolute;
transform: translateX(-50%);
top: -50px;
left: 50%;
}
`;
Full file Header.jsx
import React from "react";
import { css } from "emotion";
import { useTheme } from "emotion-theming";
const Header = () => {
const theme = useTheme();
const headerStyle = css`
position: absolute;
top: 0;
right: 0;
`;
const navStyle = css`
width: 1093px;
position: relative;
background-color: ${theme.colors["bg-nav"]};
display: flex;
justify-content: right;
height: 109px;
`;
const accountStyle = css`
width: 428px;
height: 109px;
background-color: ${theme.colors["alt-red"]};
`;
const ulStyle = css`
box-sizing: border-box;
padding: 0;
display: flex;
margin: 0;
font-size: 1rem;
align-items: center;
list-style: none;
`;
const itemStyle = css`
box-sizing: border-box;
padding: 0 30px;
`;
const linkStyle = css`
text-decoration: none;
font-family: "Montserrat";
position: relative;
font-weight: 300;
font-style: normal;
color: ${theme.colors.text};
&::after {
background-color: ${theme.colors.primary};
width: 150%;
height: 40px;
content: "";
position: absolute;
transform: translateX(-50%);
top: -50px;
left: 50%;
}
`;
return (
<header className={headerStyle}>
<nav className={navStyle}>
<ul className={ulStyle}>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Home
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Menu
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Gallery
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Testiminials
</a>
</li>
<li className={itemStyle}>
<a className={linkStyle} href="/">
Contact Us
</a>
</li>
</ul>
<div className={accountStyle}></div>
</nav>
</header>
);
};
export default Header;
I think it depends on what library you are using for routing because each one does it differently. Assuming you are using the most popular (afaik) React Router library, then it would be a case of using a <NavLink> instead of a <Link>. When the current URL matches the <NavLink> you can add a custom class to activeClassName.
Here’s a link to what I’m referring to: https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom
With that in mind, here’s a simplified version of what you’d need to do:
import React from "react";
import { css } from "emotion";
import { useTheme } from "emotion-theming";
import { NavLink } from 'react-router-dom';
const Header = () => {
const activeClass = css`
/* active css styles go here */
`;
return (
<header>
<nav>
<ul>
<li>
<NavLink exact to="/" className={linkStyle} activeClassName={activeClass}>
Home
</NavLink>
</li>
<li>
<NavLink to="/menu" className={linkStyle} activeClassName={activeClass}>
Menu
</NavLink>
</li>
</ul>
</nav>
</header>
);
};
export default Header;

Vue <router-view/> loads header components twice

I am building a simple vue app and I encountered a strange issue where the components in my tag are rendered a second time inside the tag.
Originally, the and components were not in a header tag but they appeared below the component.
App.vue
<template>
<div id="app">
<header><app-logo/><nav-bar/></header>
<section class="container">
<router-view/>
</section>
</div>
</template>
<script>
import AppLogo from './components/AppLogo.vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
Home,
AppLogo
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
nav-bar component:
<template>
<div>
<h1> TFJS/Vue Examples </h1>
<div v-for="page in pages" v-bind:key="page">
<div>
<div>
<router-link to='/basic-logistic-regression'> {{ page }} </router-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
pages: ['/BasicLogisticRegression']
}
}
}
</script>
I want to have nav-bar component appear above the router view at all times.
I solved this problem by using a mounted method called loadHome() which uses this.$router.push('/home') to programatically force the router-view to load the homepage component.
here is the code
App.vue
<template>
<div id="app">
<div class="routing">
<header><app-logo/><nav-bar/></header>
</div>
<section class="container">
<router-view/>
</section>
</div>
</template>
<script>
import AppLogo from './components/AppLogo.vue'
import NavBar from './components/NavBar.vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: {
Home,
AppLogo,
NavBar
},
methods: {
loadHome: function(){
this.$router.push('/home')
}
},
mounted: function(){
this.loadHome()
}
}
</script>

Categories

Resources