React with TS can't see any contect inside background wrapper component - reactjs

Here is the register component code -
const RegisterView = () => {
return (
<Background>
<h1>ddd</h1>
</Background>
);
};
The background scss -
.mainContainer {
display: flex;
flex-direction: row;
min-height: 80vh;
min-width: 140vh;
align-items: center;
justify-content: center;
background-color: map-get($colors, primary);
padding: 100px;
position: relative;
z-index: 10;
&:after {
background-color: #fff;
border-radius: 15px;
content: '';
position: absolute;
top: 90px;
left: 140px;
right: 140px;
bottom: 90px;
z-index: -1;
}
}
Background component view.tsx -
import classes from './Background.module.scss';
const BackgroundView = () => {
return (
<div className={classes['mainContainer']}></div>
);
};
BackgroundView.displayName = 'Background';
BackgroundView.defaultProps = {};
export default BackgroundView;
Background component tsx -
import BackgroundView from './Background.view';
const Background = () => {
return (
<BackgroundView />
);
};
Background.displayName = 'Background';
Background.defaultProps = {};
export default Background;
The Background component should be a wrapper for all other components. Here is what I'm getting right now -
I can't get any content inside the component, what is the problem?

You've wrapped BackgroundView in a Background component you've written like this:
const Background = () => {
return (
<BackgroundView />
);
};
That throws away any children you've provided to the Background component. If you want to put those children in the BackgroundView, you have to do that explicitly:
const Background = ({children}) => {
return (
<BackgroundView>{children}</BackgroundView>
);
};
You have the same problem with BackgroundView, so:
const BackgroundView = ({children}) => {
return (
<div className={classes['mainContainer']}>{children}</div>
);
};
It's also not clear why you have Background at all. You could just use BackgroundView directly.
Just as a side note, there's no need for the () around JSX elements (provided you start the JSX element on the line with the return, not the next line):
const Background = ({children}) => {
return <BackgroundView>{children}</BackgroundView>;
};
and in fact, if you like, you can use the concise form of the arrow function:
const Background = ({children}) => <BackgroundView>{children}</BackgroundView>;
but those are both just style things, you may prefer to do it differently.

Related

How can I show the uploaded image in React?

I'm going to upload an image with react now. When I selected the image and received the value of the selected image in state, I got an array like below. But how do I approach this array to see this selected image? If you look at the picture, there is no path to the picture in the array, so I want to know which value to choose to see the picture. I'd appreciate it if you let me know, thanks.
import React from 'react'
import { useState } from 'react';
import styled from 'styled-components';
function MakeModal() {
const fileInput = React.useRef(null);
const [isfile,setIsfile] = useState("");
const handleButtonClick = e => {
fileInput.current.click();
};
const handleChange = e => {
setIsfile(e.target.files[0]);
console.log(e.target.files[0]);
};
const objectUrl = URL.createObjectURL(isfile);
console.log('check',objectUrl)
return (
<Modal>
<div>
<div>
<div>
<div>
<input
type="file"
style={{display:'none'}}
ref={fileInput}
onChange={handleChange}
multiple={true}/>
<button
className='box9_2_3_3_2'
onClick={handleButtonClick}>
choose img
</button>
</div>
</div>
</div>
</div>
</Modal>
)
}
export default MakeModal;
const Modal = styled.div`
display: ${props=>props.isModal===true?'block':'none'};
position: fixed;
background-color: rgba(0,0,0,0.65);
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 500343;
.box9_2_3_3_2 {
background-color: rgb(0,149,246)!important;
border: 1px solid transparent;
border-radius: 4px;
color: white;
position: relative;
-webkit-appearance: none;
background: none;
box-sizing: border-box;
cursor: pointer;
display: block;
}
`
You only need to create an ObjectUrl from your file like this :
const objectUrl = URL.createObjectURL(file); // or file[0] if it's an array
...
<img src={objectUrl} ... />
...
A good practise is to revoke the URL when the compenent unmount, or when the file change. One exemple is to do it like this, it depends on your logic :
const [isFile, setIsFile] = useState('');
const [preview, setPreview] = useState('');
useEffect(() => {
if (isFile) {
const objectUrl = URL.createObjectURL(isFile); // create here
setPreview(objectUrl);
}
return () => URL.revokeObjectURL(isFile); // And revoke on unmount
}, [isFile]); // or whatever you called the variable you put the file in
return (
...
<img src={preview} ... />
...
)

Resizing components using .map() and inline event handlers

I'm trying to implement data-rendered resizable components using the example below (first code snippet). I tried writing it with useRef but that would require putting a hook inside a loop which is against React's documentation.
This is the snippet that contains desired functionality.
const App = () => {
const ref = React.useRef(null);
const refRight = React.useRef(null);
React.useEffect(() => {
const resizeableEle = ref.current;
const styles = window.getComputedStyle(resizeableEle);
let width = parseInt(styles.width, 10);
let x = 0;
resizeableEle.style.top = '20px';
resizeableEle.style.left = '20px';
// Right resize
const onMouseMoveRightResize = (event) => {
const dx = event.clientX - x;
x = event.clientX;
width = width + dx;
resizeableEle.style.width = `${width}px`;
};
const onMouseUpRightResize = () => {
document.removeEventListener('mousemove', onMouseMoveRightResize);
};
const onMouseDownRightResize = (event) => {
x = event.clientX;
resizeableEle.style.left = styles.left;
resizeableEle.style.right = null;
document.addEventListener('mousemove', onMouseMoveRightResize);
document.addEventListener('mouseup', onMouseUpRightResize);
};
// Add mouse down event listener
const resizerRight = refRight.current;
resizerRight.addEventListener('mousedown', onMouseDownRightResize);
return () => {
resizerRight.removeEventListener('mousedown', onMouseDownRightResize);
};
}, []);
return (
<div className="container">
<div ref={ref} className="resizeable">
<p>Hello this is text</p>
<div ref={refRight} className="resizer resizer-r"></div>
</div>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);
.container {
border-radius: 5px;
width: 100vw;
height: 100vh;
background: #FFBC97;
position: relative;
}
.resizeable {
position: absolute;
top: 20px;
left: 150px;
border: 2px solid #533535;
width: 100px;
height: 100px;
border-radius: 3px;
display:block;
/* justify-content: center; */
align-items: center;
min-width: 15px;
min-height: 15px;
text-overflow: ellipsis !important;
white-space: nowrap !important;
overflow: hidden !important;
}
.resizer {
position: absolute;
background: black;
}
.resizer-r {
cursor: col-resize;
height: 100%;
right: 0;
top: 0;
width: 2px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
Basically I'm trying to reproduce the same resize functionality but instead of using useRef I want to define event listeners inline like this <div onMouseMove={handleMouseMove}>. Mainly because having hooks inside a loop is not a good practie in React.
I want it to look somewhat like the second snipped below, Is this the right approach?
const App = () => {
const data = ['item1', 'item2', 'item3', 'item4', 'item5'];
return (
<div className="App">
{data.map((x, i) => {
function handleMouseDown(e) {
console.log('trying to resize');
}
function handleMouseUp() {
console.log('handling mouseUp');
}
const onMouseMoveRightResize = (e) => {
console.log('moving...');
};
return (
<div className="item" key={data[i]}>
{x}
<div key={`i${i}`} className="resizer" onMouseMove={onMouseMoveRightResize} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp}></div>
</div>
);
})}
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);
.App {
text-align: center;
}
.item{
position: relative;
border: 1px solid black;
width: 300px;
margin: 10px auto;
border-radius: 3px;
cursor: pointer;
}
.resizer {
position: absolute;
background: black;
cursor: col-resize;
height: 100%;
right: 0;
top: 0;
width: 5px;
}
<div id="root"></div>
<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>
I tried reproducing that many times. I managed to change the widths of the components but I keep failing at implementing smooth resize functionality. Can anyone help me, please?
So to make sure we're answering this correctly - first of if your intention is to render this same resizable component multiple times you can just move that logic to another component and rerender it as shown in this codesandbox.
In case you wish to do something custom for each item, for these 3 functions function handleMouseDown, handleMouseUp, onMouseMoveRightResize then we could just pass these functions to the child, and expect the child to pass in the required props and handle the change - additionally from the index we know which item got clicked, resized, released. Codesandbox link (Open the console and the logs should make it clear).
So the gist of it is you can create another component which can be rendered in the map function circumventing the requirement to not use hooks directly in map functions.
App.js
import "./styles.css";
import ResizableComponent from "./ResizableComponent";
const App = () => {
const data = ["item1", "item2", "item3", "item4", "item5"];
return (
<div className="container">
{data.map((x, index) => (
<ResizableComponent index={index} key={x} />
))}
</div>
);
};
export default App;
ResizableComponent.js
import { useEffect, useRef } from "react";
const ResizableComponent = ({
index,
handleMouseDown,
handleMouseUp,
handleMouseMoveRightResize
}) => {
const ref = useRef(null);
const refRight = useRef(null);
useEffect(() => {
const resizeableEle = ref.current;
const resizerRight = refRight.current;
if (resizeableEle && resizerRight) {
const styles = window.getComputedStyle(resizeableEle);
// let width = parseInt(styles.width, 10);
// let x = 0;
resizeableEle.style.top = `${index * 120 + 20}px`;
resizeableEle.style.left = "20px";
// Right resize
const onMouseMoveRightResize = (event) => {
// const dx = event.clientX - x;
// x = event.clientX;
// width = width + dx;
// resizeableEle.style.width = `${width}px`;
handleMouseMoveRightResize();
// pass whatever props you want to the parent component
};
const onMouseUpRightResize = () => {
handleMouseUp();
document.removeEventListener("mousemove", onMouseMoveRightResize);
};
const onMouseDownRightResize = (event) => {
handleMouseDown();
// pass wahtever props you want to the parent component
// x = event.clientX;
// resizeableEle.style.left = styles.left;
// resizeableEle.style.right = '';
document.addEventListener("mousemove", onMouseMoveRightResize);
document.addEventListener("mouseup", onMouseUpRightResize);
};
resizerRight.addEventListener("mousedown", onMouseDownRightResize);
return () => {
if (resizerRight)
resizerRight.removeEventListener("mousedown", onMouseDownRightResize);
};
}
}, [handleMouseDown, handleMouseMoveRightResize, handleMouseUp, index]);
return (
<div ref={ref} className="resizeable">
<p>Hello this is text</p>
<div ref={refRight} className="resizer resizer-r"></div>
</div>
);
};
export default ResizableComponent;
Also by uncommenting the code in the second solution you can have the default resize functionality and additionally do something else in the handleMouseDown, handleMouseUp, handleMouseMoveRightResize functions.
I will try to find a more viable solution if there's one but I think this should do it.

handling events on custom components

I have these files:
button.module.css
.base {
display: flex;
font-size: 16px;
font-family: "Helvetica Neue";
align-items: center;
justify-content: center;
padding: 6px 12px 6px 12px;
width: 50px;
border-radius: 6px;
}
.normal {
composes: base;
color:black;
background-color: #aeeeb7;
border: 1px solid #42924d;;
}
.danger {
composes: base;
color:black;
background-color: rgb(253, 128, 128);
border: 1px solid rgb(196, 108, 108);
}
button.js
import classes from './button.module.css';
const ButtonTypes = {
'normal': classes.normal,
'danger': classes.danger
};
const Button = (props) => {
const className = ButtonTypes[props.type] ? ButtonTypes[props.type] : classes.normal;
return <div role="button" className={className} ...props>{text}</div>;
}
export default Button;
app.js
import Button from './button';
const App = () => {
const handleClick = () => {
console.log('app');
}
const handleMouseOver = () => {
console.log('mouse-over');
}
...
return (
<div>
<Button type="normal" onClick=(handleClick) onMouseOver={handleMouseOver} ...>
</div>
);
}
export default Button;
I am changing the class of the button depending on the "type" property. (It could be other components not just a button)
How should I handle events on the custom component? Is the way I am passing them right now to that div inside fine or I should do it differently?
I want to create some custom components and I am trying to verify I am doing it the right way.
One suggestion here. Instead of spreading all props in button. You can destructure out the required props and then spread the rest props.
import classes from "./button.module.css";
const ButtonTypes = {
normal: classes.normal,
danger: classes.danger
};
const Button = ({ type, ...rest }) => {
const className = ButtonTypes[type] ? ButtonTypes[type] : classes.normal;
return (
<div role="button" className={className} {...rest}>
{text}
</div>
);
};
export default Button;

How to add "active" class to styled components in React

I'm learning React and i just founded about styled-components and i would like to refactor my code into styled components.
Maybe i didn't understand it at all but i'm trying to make add/remove class on "toggle"
For example:
button--active
Here is what i've tried so far:
render() {
const {active, toggleHamburgerActive } = this.props;
return (
<div>
<HamburgerButtonContainer active={active} onClick={toggleHamburgerActive}/>
</div>
styles:
const buttonStyles = css`
border: 1px solid red;
`;
const getButtonStyles = active => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = css`
border: 10px solid green;
`;
export const HamburgerButtonContainer = styled.button`
${getButtonStyles}
`;
#EDIT
To make it more clear. active is changing on click but styles are not.
I think you just forgot to destructure your props:
const getButtonStyles = /* this here ---> */({active}) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const getButtonStyles = /* props is passed here, not only active ---> */props =>
You can access props by passing a callback in an expression as you did.
styled.button`
${props => ...} // you passed the callback here, so props is passed to it, not only active
`
Or if you prefer
styled.button`
${props => getButtonStyles(props.active)}
`
You haven't called your function using active as a param. And You should organise your code like below to pass the active as a prop.
const HamburgerButtonContainer = ({ onClick, active }) => {
const buttonStyles = `
border: 1px solid red;
`;
const getButtonStyles = (active) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = `
border: 10px solid green;
`;
const StyledHamburgerButtonContainer = styled.button`
${getButtonStyles(active)}
`;
return <StyledHamburgerButtonContainer onClick={onClick} />;
};

Styled-components: Styles are not applied when trying to style already styled component

I'm trying to style my component which was styled already. But styles in the new rules are not applied in output CSS.
Can I style component that I already styled?
Thanks you in advance for your help.
EDIT: Add rest of LanugageChooser definition
// COMPONENT THAT I'M TRYING TO STYLE
const LanguageChooser = () => {
const Container = styled.div`
display: flex;
align-items: center;
height: 36px;
& > div:not(:last-child) {
margin-right: 5px;
}
`;
return (
<Container>
<Flag { ...languages.pl }/>
<Flag { ...languages.en }/>
</Container>
)
}
const Flag = ({ flag, language }) => {
const { i18n } = useTranslation();
const Button = styled.div`
cursor: pointer;
font-size: 24px;
transition: .2s all;
&:hover {
font-size: 36px;
}
`;
return (
<Button onClick={ () => i18n.changeLanguage(language) }>{ flag }</Button>
)
}
// TRYING ADD MARGIN LEFT, BUT THERE IS NO RESULT.
// ANY OTHER CSS PROPERTY ARE NOT APPLYING
const Navbar = ({ color }) => {
...
const StyledLanguageChooser = styled(LanguageChooser)`
margin-left: auto;
`;
const Nav = styled.nav`
display: flex;
align-content:center;
background: ${ color };
padding: 2px 3px;
`;
return (
<Nav className="navbar">
<StyledNavLink to="/home">...</StyledNavLink>
<StyledNavLink to="/maps">...</StyledNavLink>
<StyledNavLink to="/charts">...</StyledNavLink>
<StyledLanguageChooser/>
</Nav>
)
}
First, move the styled component outside of function scope or your style will reset on every render and you will get heavy performance issues.
Secondly, in order to apply styles, you need to pass className property.
See Styling normal React components
If you use the styled(MyComponent) notation and MyComponent does not render the passed-in className prop, then no styles will be applied.
const Container = styled.div`
display: flex;
align-items: center;
height: 36px;
& > div:not(:last-child) {
margin-right: 5px;
}
`;
const LanguageChooser = ({ className }) => {
return (
<Container className={className}>
<Flag {...languages.pl} />
<Flag {...languages.en} />
</Container>
);
};
const Button = styled.div`
cursor: pointer;
font-size: 24px;
transition: 0.2s all;
&:hover {
font-size: 36px;
}
`;
const Flag = ({ flag, language }) => {
const { i18n } = useTranslation();
return <Button onClick={() => i18n.changeLanguage(language)}>{flag}</Button>;
};

Resources