I have a question with styled components, I would like to know how to position elements from their parents, I saw that there are the following options but I do not like any.
Through props, I don't like this method because I consider that the maintainability of this is horrible since in complex cases we will have many props.
Through className, generally in styled components we don't have class since we create styled.div for example, I like to have consistency in my structure and I don't want to have class names in some and not in others.
In this case CurrentFinderLocationButton is a react component, how would you position them? Is there a way to select it and apply styles from StyledHome without className or props?
import React from "react";
import styled from "styled-components";
import CurrentLocationFinderButton from "../buttons/CurrentLocationFinderButton";
import fullLogotype from "../../assets/images/full-logotype.svg";
const Home = () => {
return (
<StyledHome>
<StyledLogotype src={fullLogotype} />
<CurrentLocationFinderButton />
</StyledHome>
);
};
const StyledHome = styled.div`
`;
const StyledLogotype = styled.img`
width: 150px;
display: block;
margin: auto;
`;
export default Home;
you can just add some styles to wrapper
const StyledCurrentLocationFinderButton = styled(CurrentLocationFinderButton)`
{any styles}
`
Finally i solved this problem binding the component class and styled components class through the props.
import React from "react";
import styled from "styled-components";
import fullLogotype from "../../assets/images/full-logotype.svg";
import CurrentLocationFinderButton from "../buttons/CurrentLocationFinderButton";
import AddressFinder from "../finders/AddressFinder";
const Logotype = ({ className }) => {
return <img className={className} alt="" src={fullLogotype} />;
};
const EntryText = ({ className }) => {
return (
<p className={className}>
Atisbalo es una app donde podrás encontrar información sobre tus locales
favoritos y enterarte de todas las promociones que oferta tu cuidad al
instante
</p>
);
};
const Home = ({ className }) => {
return (
<StyledHome className={className}>
<StyledLogotype />
<StyleEntryText />
<StyledCurrentLocationFinderButton />
<StyledAddressFinder/>
</StyledHome>
);
};
const StyledHome = styled.div``;
const StyledLogotype = styled(Logotype)`
width: 150px;
display: block;
margin: auto auto 30px auto;
`;
const StyleEntryText = styled(EntryText)`
display: block;
width: 90%;
text-align: center;
margin: auto auto 30px auto;
`;
const StyledCurrentLocationFinderButton = styled(CurrentLocationFinderButton)`
display: block;
margin: auto auto 30px auto;
`;
const StyledAddressFinder = styled(AddressFinder)`
width: 80%;
margin: auto;
`
export default Home;
Related
I want to change css width property of my element on some condition
<div className="consoleLayoutRoot-sideMenu">
<ConsoleSideMenu />
</div>
css
.consoleLayoutRoot-sideMenu .ant-menu {
padding-top: 30px;
/* background-color: #191146 !important; */
}
I am doing this way..but nothing is happening
document.getElementsByClassName("conjnjnot-sideMenjnjbhbhu.annjn ").style.width = "77px";
That's not working because you're treating a list as though it were an element. But it's also fundamentally not how you would do this in a React project.
Instead, you'd have the component re-render when the condition becomes true (perhaps by setting a state member). When rendering the div, you optionally include a style or a class name depending on whether you want the width applied:
<div className={`consoleLayoutRoot-sideMenu ${shouldHaveWidthClass ? "width-class" : ""}`}>
<ConsoleSideMenu />
</div>
...where .width-class { width: 50px; } is in your stylesheet.
Or with inline style, but inline styles are best avoided:
<div className="consoleLayoutRoot-sideMenu" style={shouldHaveWidthSetting ? { width: "50px" } : undefined}>
<ConsoleSideMenu />
</div>
Here's an example (using a class);
const {useState} = React;
const ConsoleSideMenu = () => <span>x</span>;
const Example = () => {
const [includeWidth, setIncludeWidth] = useState(false);
const toggle = ({currentTarget: { checked }}) => {
setIncludeWidth(checked);
};
return <React.Fragment>
<div className={`consoleLayoutRoot-sideMenu ${includeWidth ? "width-class" : ""}`}>
<ConsoleSideMenu />
</div>
<label>
<input type="checkbox" onChange={toggle} checked={includeWidth} />
Include width class
</label>
</React.Fragment>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
.width-class {
width: 50px;
}
.consoleLayoutRoot-sideMenu {
border: 1px solid blue;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
I have this React component. Which renders a simple HTML. I have an event handler attached to an element. On clicking that particular element I want some CSS styles to change. For that I used the code below-
import React from 'react';
import './start.css';
class Start extends React.Component {
handleEvent() {
const login = document.querySelector('.login');
const start = document.querySelector('.start')
login.style.right = '0';
start.style.left = '-100vw';
}
render() {
return (
<section className = 'page start'>
<h1>Welcome To Our App</h1>
<button onClick = {this.handleEvent}>Next</button>
</section>
)
}
}
export default Start;
My question is in the handleEvent() is it appropriate to select the elements using Document and style the elements using .style. Is there any other "react-specific" way to do this?
class Test extends React.Component {
constructor(){
super();
this.state = {
black: true
}
}
changeColor(){
this.setState({black: !this.state.black})
}
render(){
let btn_class = this.state.black ? "blackButton" : "whiteButton";
return (
<div>
<button className={btn_class}
onClick={this.changeColor.bind(this)}>
Button
</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.querySelector("#app"))
button{
width: 80px;
height: 40px;
margin: 15px;
}
.blackButton{
background-color: black;
color: white;
}
.whiteButton{
background-color: white;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
first of all yes you can use document in react for that. But "react specific" style you be something like this:
<div id="app"></div>
In css file :
button{
width: 80px;
height: 40px;
margin: 15px;
}
.blackButton{
background-color: black;
color: white;
}
.whiteButton{
background-color: white;
color: black;
}
and finally a component :
class Test extends React.Component {
constructor(){
super();
this.state = {
black: true
}
}
changeColor(){
this.setState({black: !this.state.black})
}
render(){
let btn_class = this.state.black ? "blackButton" : "whiteButton";
return (
<div>
<button className={btn_class}
onClick={this.changeColor.bind(this)}>
Button
</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.querySelector("#app"))
You can set a state to check whether the button has been clicked and change the class name
Similar approach can be used.
This is the React Specific way!
You can refer to React doc
https://reactjs.org/docs/faq-styling.html
import React from 'react';
import './start.css';
class Start extends React.Component {
constructor(props) {
super(props);
this.state = {hasButtonClicked : false};
}
handleEvent() {
this.setState({hasButtonClicked : true});
}
render() {
let clicked = this.state.hasButtonClicked;
return (
<section className = { clicked ? someCssClass :'page start'} >
<h1>Welcome To Our App</h1>
<button onClick = {this.handleEvent}>Next</button>
</section>
)
}
}
I'm new to Next and have been trying to make a page(index.js) that fetches data(countries) and then displays that data, where each returned element(country) has a button to go to a page(info.js) where that specific countries data will be displayed, was wondering if its possible to pass the props(all country data) to the info.js page? I've tried reading the documentation and watching YT videos but can't seem understand what i'm reading/watching.
index.js:
import Link from 'next/link'
Welcome.getInitialProps = async function (props) {
const res = await fetch('https://restcountries.eu/rest/v2/all')
const data = await res.json()
return {
data: data
}
}
const MyLink = props => {
return (
<p>
<Link href={`/info?name=${props.name}`} >
<a>Learn More</a>
</Link>
</p>
)
}
function Welcome(props) {
return (
<div>
<div className="main-content">
<style jsx>{`
.main-content {
width: 80%;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 5px;
}
.item {
border: 1px solid black;
text-align: center;
}
.item ul{
padding: 0;
}
.item ul li {
list-style-type: none;
}
`}</style>
{props.data.map(country => (
<div key={country.numericCode} className="item">
<h4>{country.name}</h4>
<p>Region: {country.region}</p>
<p>Population: {country.population}</p>
<MyLink name={country.name} borders={country.borders} currencies={country.currencies}/>
</div>
))}
</div>
</div>
)
}
export default Welcome
info.js:
import { withRouter } from 'next/router'
import Link from 'next/link'
const Info = (props) => {
return (
<div>
<h1>{props.router.query.name}</h1>
<Link href="/">
<a>Home</a>
</Link>
</div>
)
}
export default withRouter(Info)
In MyLink component instead of using Link you can create a normal div (style it like a link) and onClick of that div push it to different page using nextjs router:
//import useRouter
import { useRouter } from 'next/router'
//then call it
const router = useRouter()
const MyLink = props => {
return (
<p onClick={() => {
router.push({
pathname: `/info?name=${props.name}`,
query: { data: //data to pass },
})
}}>
<a>Learn More</a>
</p>
)
}
You can access that data in the location object in the query key
import {useLocation} from ""
const location = useLocation()
const data = location.query
Currently, in my app, when I click on the button, it generates a random image but it bunches up everything like so. I'd like the image to show up, which are all in different sizes, have the dog's name right below it, centered and then the button below that.
Code
import * as React from "react";
import { render } from "react-dom";
import axios from "axios";
import "./styles.css";
function App() {
const [images, setImage] = React.useState("");
const [text, setText] = React.useState("");
function btnClick() {
axios
.all([axios.get("https://dog.ceo/api/breeds/image/random"),
axios.get("https://dog.ceo/api/breeds/list/all")
])
.then(axios.spread((response) => {
setImage(response.data.message);
setText(response.data.message.split('/')[4]);
}))
.catch(err => {
console.log("Error happened during fetching!", err);
});
}
return (
<div className = "App">
<img className = "Img" src={images} alt="broken"/>
<button className = "Button" onClick = {btnClick}>Doggie!</button>
<strong>{text}</strong>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
CSS
.App {
font-family: sans-serif;
text-align: center;
}
.Button {
display: flex;
}
.Img {
max-width:100%;
height:auto;
max-height:100%;
}
Re-arranging the element should solve the issue, wrap the name with <p></p> to display it on a new paragraph.
import React from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [images, setImage] = React.useState("");
const [text, setText] = React.useState("");
function btnClick() {
axios
.all([
axios.get("https://dog.ceo/api/breeds/image/random"),
axios.get("https://dog.ceo/api/breeds/list/all")
])
.then(
axios.spread(response => {
setImage(response.data.message);
setText(response.data.message.split("/")[4]);
})
)
.catch(err => {
console.log("Error happened during fetching!", err);
});
}
return (
<div className="App">
<img src={images} alt="broken" />
<p><strong>{text}</strong></p>
<button className="button" onClick={btnClick}>
Doggie!
</button>
</div>
);
}
You should rearrange your rendered elements, so it goes <img/> <strong/> <button />.
Then in your CSS, make sure the elements that are inline natively become block.
See snippet below.
Note: left out React as it's not related to your issue so ignore class usage.
.App {
font-family: sans-serif;
text-align: center;
}
.App strong {
display: block;
}
.Button {
width: 100%;
text-align: center;
}
.Img {
max-width:100%;
height:auto;
max-height:100%;
display: block;
}
<div class="App">
<img class="Img" src="https://i.stack.imgur.com/0WaeI.png" alt="broken"/>
<strong>{text}</strong>
<button class="Button" onClick={btnClick}>Doggie!</button>
</div>
Flexbox
If you would prefer to use flexbox styling see this thorough post about it.
I'm trying to trap an onclick method on a React component to create a React Modal.
I've added react-overlay as a dependency and added it to my file.
import Modal from 'react-overlays';
This is the anchor element,
<a href="#" onClick={this.handleClick} data-id={image.id}>
This is the handleclick method,
handleClick(event) {
event.preventDefault();
let mediaId = event.currentTarget.attributes['data-id'].value;
this.setState({ overlay: <Modal show={this.state.showModal} onHide={this.close} mediaId={mediaId}/> });
}
I get the following error,
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.(…)
I recently had this problem and got around it by creating a Modal-component.
import Modal from 'react-modal'
export default class CustomModal extends React.Component {
constructor () {
super();
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.state = {
open: false
}
}
openModal () { this.setState(
{open: true});
$(function(){
$("#custom-modal").appendTo("body");
});
}
closeModal () {
this.setState({open: false});
}
componentDidMount(){
$(function(){
$("#custom-modal").appendTo("body");
});
}
render () {
return (
<div>
<button onClick={this.openModal}>My modal</button>
<Modal id="custom-modal" isOpen={this.state.open} onRequestClose={this.closeModal}>
// Modal body content here
<button onClick={this.closeModal}>Close</button>
</Modal>
</div>
);
}
}
And then using it like this:
import CustomModal from '../components/CustomModal'
...
<li><CustomModal/></li>
Hope this is of any help.
Your state should contain information that allows you to render the modal, but not the modal itself.
It's highly unusually to store components in state.
Try this:
Store a flag in your state to indicate whether the modal should be shown.
Set the flag in handleClick()
In render(), render the modal if the flag is set.
Let me know if you need an example.
Looks like you're importing undefined..
Also, take a look at https://github.com/fckt/react-layer-stack. This is universal and clean way to solve the "modal problem" in React. Demo - https://fckt.github.io/react-layer-stack/
In case anyone still has an issue with this, a modern approach is to build the modal using React hooks. as shown below
import React from 'react';
import './modal.css';
import FontAwesome from 'react-fontawesome';
const Modal = (props) => {
const { closeModal } = props;
const closeicon = () => (
<FontAwesome
name="times"
onClick={closeModal}
style={{
color: '#000000',
padding: '10px',
cursor: 'pointer',
backgroundColor: 'transparent',
border: 0,
position: 'absolute',
top: '0.3rem',
right: '0.5rem',
}}
/>
);
return (
<div className="overlay">
<div className="content">
{ closeicon() }
{props.children}
</div>
</div>
);
};
export default Modal;
The css is as shown below
.overlay {
position: fixed;
display: block;
overflow: auto;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5);
z-index: 999;
cursor: pointer;
}
.content {
margin: 15% auto;
background-color: white;
border-radius: 0.25rem;
width: 50vw;
padding: 2rem;
position: relative;
}
So you can use the modal component like this
const [status, setStatus] = useState(false);
//this button will trigger the modal
<button onClick={() => setStatus(true)}>Open Modal</button>
{
status && (
<Modal closeModal={() => setStatus(false)}><p>hello worls</p></Modal>
)
}
No need to worry about responsiveness It's been taken care of in the styling.
For further explanation, you can check this link
https://dev.to/adeyemiadekore2/how-to-build-a-reusable-and-responsive-modal-in-react-from-scratch-1o0f