import React from "react";
import { useSelector } from "react-redux";
import { selectData } from "../features/dataSlice";
import ProductCard from "./ProductCard";
import { Grid } from "#material-ui/core";
import styled from "styled-components";
import style from "../style.css";
function Product() {
const products = useSelector(selectData);
const renderproducts = products.map((product) => {
//const { id, title, price, description, category, image, rating } = product;
return <ProductCard data={product} />;
});
return (
<Container>
<div>{renderproducts}</div>
</Container>
);
}
export default Product;
const Container = styled.div`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
`;
-------------------------------------
import React from "react";
import Product from "./Product";
import styled from "styled-components";
import { Grid } from "#material-ui/core";
function ProductCard(props) {
const { data } = props;
return (
<Container>
<img src={data.image} />
</Container>
);
}
export default ProductCard;
const Container = styled.div`
padding-top: 60px;
img {
width: 100px;
height: 100px;
}
`;
const Card = styled.div`
img {
width: 60px;
height: 60px;
}
`;
I need to display all the images from the products array which Iam fetching from an API as Grid View. Above is the code for the ProductCard.js & Product.js components. I have tried to add the grid view styling in the ProductCard component also. But it just does'nt display as Grid. Please help me.
You can use grid-like.
<Grid container spacing={2}>
{products.map((p,i)=>( <Grid key={i} item xs={8}>
< ProductCard/>
</Grid>)
}
</Grid>
</Grid>
for more details, you can check https://mui.com/components/grid/
Related
I have a component like this:
// MyComponent.tsx
export function MyComponent(): React.ReactElement {
return <Wrapper>
<Text>
hello there
</Text>
<AnotherText>
bye bye
</AnotherText>
</Wrapper>
}
export const Wrapper = styled.div`
color: #FEB240;
background: #f5f5f5;
padding-bottom: 5rem;
padding-left: 7rem;
padding-right: 7rem;
gap: 2rem;
`;
export const Text = styled.span`
width: 50%;
cursor: pointer;
color: rgba(28, 33, 120, 1);
`;
export const AnotherText = styled.span`
color: red;
`;
I want to be able to style the wrapper. I tried to like this (from this answer Styling Nested Components in Styled-Components), but I don't see any change:
// AnotherPlace.tsx
const NewlyStyledMyComponent = styled(MyComponent)`
${Wrapper} {
color: brown;
background: magenta;
}
`;
It seems that MyComponent also need to take (generated) className as props and assign it to the root wrapping element to make the nested styles to work as expected.
Simplified live demo: stackblitz
A basic example in MyComponent:
import styled from 'styled-components';
interface Props {
className?: string;
}
export const Wrapper = styled.div`
background-color: hotpink;
`;
export const Text = styled.span`
color: #fff;
`;
function MyComponent({ className }: Props) {
return (
<div className={className}>
<Wrapper>
<Text>Hello</Text>
</Wrapper>
</div>
);
}
export default MyComponent;
And at where it is imported and used:
import styled from 'styled-components';
import MyComponent, { Wrapper, Text } from './MyComponent';
const NewlyStyledMyComponent = styled(MyComponent)`
margin-bottom: 7px;
${Wrapper} {
background-color: indigo;
}
${Text} {
color: gold;
}
`;
function App() {
return (
<div>
<NewlyStyledMyComponent />
<MyComponent />
</div>
);
}
export default App;
There are indeed 2 issues:
To style a custom React component (even just so that its nested components can be styled), you always need to take a className prop and to apply it on one of your rendered elements, as explained in styled-components docs:
The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.
To style nested components, the className of the parent element must be applied on a parent DOM element as well; that is why JohnLi's answer has to add an extra <div className={className}> around the <Wrapper>.
But in your case, you could just style MyComponent and apply the className on the <Wrapper>:
export function MyComponent({
className
}: {
className?: string;
}): React.ReactElement {
return (
// Apply className directly on the Wrapper
<Wrapper className={className}>
This text can be re-colored
<Text>hello there can be re-colored if styling nested Text</Text>
<AnotherText>bye bye</AnotherText>
</Wrapper>
);
}
const NewlyStyledMyComponent = styled(MyComponent)`
/* Directly style MyComponent */
color: brown;
background: magenta;
/* Styling of nested components */
${Text} {
color: white;
}
`;
Demo: https://codesandbox.io/s/vibrant-worker-05xmil?file=/src/App.tsx
I am trying to create an element in React, but I cannot get it to be visible. It shows up in the Elements tab of the Chrome developer console, but when I hover over it there it doesn't even show a location. I have other custom elements that work fine, it is this in particular that is not rendering. Here is the code defining the element:
import React from "react";
import ReactDom from "react-dom";
const Modal = (props) => {
const [domReady, setDomReady] = React.useState(false)
React.useEffect(() => {
setDomReady(true)
})
return domReady?ReactDom.createPortal(
<>
<div className="modal">
TEST
</div>
<div onClick={() => {}} className="backdrop">
</div>
</>,
document.getElementById('modal-root')
):null
}
export default Modal;
Here is the CSS that affects it, though it is worth noting that even without this CSS I see nothing:
.modal {
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
border-radius: 6px;
background-color: white;
padding: 1rem;
text-align: center;
width: 30rem;
z-index: 10;
position: fixed;
top: 0;
left: 0;
}
.backdrop {
position: fixed;
z-index: 1;
background-color: rgba(0, 0, 0, 0.75);
width: 100%;
height: 100vh;
top: 0;
left: 0;
}
Edit: Here is the file which uses the component:
import { useState } from 'react';
//import Loading from '../Loading/Loading';
import './Income.css';
import { useNavigate } from 'react-router-dom';
import IncomeRow from '../../components/IncomeRow/IncomeRow';
import Button from '../../components/Button/Button';
import Modal from '../../components/Modal/Modal';
const Income = () => {
//Initializing
const navigate = useNavigate();
// modal visibility states
const [editModalVisible, setEditModalVisibility] = useState(false);
const [deleteModalVisible, setDeleteModalVisibility] = useState(false);
const [addModalVisible, setAddModalVisibility] = useState(false);
// show modal to edit income
const onEditClick = () => {
setEditModalVisibility(true);
}
const onDismissEditModal = () => {
setEditModalVisibility(false);
}
//returning JSX
return (
<>
<div className='Incomes'>
{/* TODO: make these autogenerate from database */}
<IncomeRow name="income 1" source="Company 1" date="1/1/2022" amount={123.45} id="1" editFunction={onEditClick}/>
<IncomeRow name="income 2" source="Company 2" date="7/31/2022" amount={420.69} id="2"editFunction={onEditClick}/>
</div>
<Button text="Add Income"/>
<Modal dismissModal={onDismissEditModal}/>
</>
);
}
export default Income
Here is App.js, which holds the base of the layout:
import React, { useState} from 'react';
import './App.css';
import Navbar from './components/Navbar/Navbar';
import 'bootstrap/dist/css/bootstrap.min.css';
//import { ThemeContext, themes } from './context/themeContext';
import { Outlet, useNavigate} from 'react-router-dom';
function App() {
return (
<div className="App">
<Navbar/>
<div className='body'>
<div id='modal-root'>
<Outlet/>
</div>
</div>
</div>
);
}
export default App;
Here:
Open the app in desktop width, notice the div has green background
Reduce browser width to mobile, the div background should change to gray
Again, increase browser width to desktop, notice the gray background remains, instead of green
What should have happened
The background in last step should be green as in the first step, isn't it?
Logging value of isMobile does seem to show it is being updated.
Here is also code:
import React from 'react';
import styled from 'styled-components';
import { useMediaQuery } from 'react-responsive';
let MenuItem = styled.div`
height: 100px;
width: 100px;
border:1px solid red;
background-color: green;
// Select those items which are children of .submenu
.submenu & {
background-color: ${({ isMobile }) => {
return isMobile && 'lightgray';
}};
}
`;
function App() {
const isMobile = useMediaQuery({ query: '(max-width: 524px)' });
return (
<div>
<div className="submenu">
<MenuItem isMobile={isMobile}>test</MenuItem>
</div>
</div>
);
}
export default App;
import React, {useEffect, useState} from 'react';
import styled from 'styled-components';
import {useMediaQuery} from 'react-responsive';
let MenuItem = styled.div`
height: 100px;
width: 100px;
border:1px solid red;
background-color: green;
`;
function App() {
const isMobile = useMediaQuery({query: '(max-width: 524px)'});
const [color, setColor] = useState('green');
useEffect(() => {
if (isMobile) setColor('silver');
else setColor('green');
}, [isMobile])
return (
<div>
<div className="submenu">
<MenuItem style={{background: color}} isMobile={isMobile}>test</MenuItem>
</div>
</div>
);
}
export default App;
You could re-write this as:
const MenuItem = styled.div`
height: 100px;
width: 100px;
border:1px solid red;
background-color: green;
`;
const SubMenu = styled.div`
${MenuItem} {
background-color: ${({ isMobile }) => (isMobile ? `red` : 'lightgray')};
}
`;
function App() {
const isMobile = useMediaQuery({ query: '(max-width: 524px)' });
return (
<>
<SubMenu isMobile={isMobile}>
<MenuItem>MenuItem in SubMenu</MenuItem>
</SubMenu>
<MenuItem>MenuItem</MenuItem>
</>
);
}
Stackblitz
It is the correct answer:
https://stackblitz.com/edit/react-t7gqwx?file=src%2FApp.js,src%2Findex.js
You shouldn't use .submenu &.
I am working on a project which will feature a leaderboard with player icons, name and scores.
Here is my initial design that im trying to implement.
Im using cards to hold each element and will eventually will be inserting data from my DB, however rn I'm just trying to get the design skeleton together all smooth. I can get the text working and aligned fine but cant figure out how to it with text. Before I was just using the cards for text and the images as its own element, it worked fine til I tried to put more than one row.
Now when I'm trying to put the image in as a card, it's just printing info about the image instead of the actual image. I'm quite new to React so sorry if its a simple solution. I've been playing with this all day and cant find a solution that works for me.
Heres the code so far! Thanks so much for taking the time to read and any advice is greatly appreciated!
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import dogicon from './assets/doggo.png'
import './index.css';
export const Grid = styled.div`
`;
export const Row = styled.div`
display: flex;
background-color: #c3b0d3;
display: block ruby;
`;
export const Col = styled.div`
flex: ${(props) => props.size};
`;
const CardStyle = styled.div`
display: block ruby;
padding-left: 30px;
padding-right: 30px;
`;
console.log(dogicon);
const LeaderboardHeader = () => {
return (
<div className="leadheader">
<h2>LEADERBOARD</h2>
</div>
)
}
class Card extends React.Component {
render(){
return (
<div className="card">
<p>{this.props.name}</p> <p>{this.props.score}</p> <p>{this.props.icon}</p>
</div>
)
}
}
class App extends React.Component {
// fires before component is mounted
constructor(props) {
// makes this refer to this component
super(props);
// set local state
this.state = {
name: "PLAYER 1",
score: "200",
icon: require('./assets/doggo.png'),
};
}
render() {
const {name} = this.state;
const{score} = this.state;
const{icon} = this.state;
return (
<div className="container">
<LeaderboardHeader />
<Grid>
<Row>
<CardStyle>
<Col size={1}>
<Card icon={icon}/>
</Col>
</CardStyle>
<CardStyle>
<Col size={1}>
<Card name ={name} />
<Card name ={name} />
<Card name ={name} />
</Col>
</CardStyle>
<CardStyle>
<Col size={1}>
<Card score={score} />
<Card score={score} />
<Card score={score} />
</Col>
</CardStyle>
</Row>
</Grid>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Index.css
#import url('https://fonts.googleapis.com/css2?family=Passion+One&display=swap');
body {
font: 50px;
font-family: 'Passion One', cursive;
margin: 20px;
background: #7E549F; overflow: hidden;
text-align: center;
}
.container{
width: 550px;
}
.leadheader {
margin-top: 100px;
background-color: #422D53;
color: #C3B0D3;
text-align: center;
width: 100%;
height: 50px;
font-size: 45px;
text-align: center;
border-radius: 5px 5px 0 0;
margin: 0;
padding-bottom: 25px;
}
.card {
background-color: #C3B0D3;
color: #2A1D34;
margin: 0 auto;
padding: 100px 0;
font-size: 40px;
}
You should use that image data in the src attribute of an <img> tag. Since you are using <p>{this.props.icon}</p> it is coerced to string, hence displaying the text value of the image.
So, this would be the final result:
class Card extends React.Component {
render(){
return (
<div className="card">
<p>{this.props.name}</p> <p>{this.props.score}</p> <img src={this.props.icon} />
</div>
)
}
}
I am using nextjs to compile my code and antd framework. I am unable to style the positioning of my button, also I want my start button to trigger a set of buttons but for some reason it does not work. Below is my code
import React, { Component } from "react";
import Layout from "./Layout";
import { Radio } from "antd";
export default class PositiveAffirmation extends Component {
state = {
changeButton: false
};
toggleChangeButton = e => {
this.setState({
changeButton: e.target.value
});
};
render() {
const { changeButton } = this.state;
return (
<Layout>
<Radio.Group
defaultValue="false"
buttonStyle="solid"
onChange={this.changeButton}
className="radio-buttons"
>
<Radio.Button value={true}>Start</Radio.Button>
<Radio.Button value={false}>Stop</Radio.Button>
</Radio.Group>
{changeButton && (
<Button.Group size={size}>
<Button type="primary">Happy</Button>
<Button type="primary">Sad</Button>
<Button type="primary">Fullfiled</Button>
</Button.Group>
)}
<style jsx>{`
Radio.Button {
font-size: 100px;
margin-left: 20px;
margin-top: 5px;
margin-bottom: 5px;
display: flex;
justify-content: center;
}
`}</style>
</Layout>
);
}
}
you are calling just wrong fn change onChange={this.changeButton} to onChange={this.toggleChangeButton}