How to make functional components into class components? - reactjs

I have buttons that slide the page down by clicking and then this part becomes a different color thanks to CSS.
But the fact is that these components are functional and I need class components.
How to make functional components into class components?
React:
const ScrollButton = props => {
const onClick = () => window.scrollTo({
top: props.scrollTo,
behavior: 'smooth',
});
return (
<div className="down" style={{ top: `${props.top}px` }}>
<div className="down-text">Scroll to {props.scrollTo}
<button onClick={onClick}>❯</button>
</div>
</div>
);
};
const App = () => (
<div className="container">
<ScrollButton scrollTo={500} top={50} />
<ScrollButton scrollTo={1000} top={100} />
<ScrollButton scrollTo={2000} top={200} />
</div>
);
ReactDOM.render(<App />, document.getElementById('app'));
СSS:
body {
height: 100vh;
margin: 0;
}
.container{
background: linear-gradient(to bottom, yellow, red);
height: 3000px;
width: 100%;
}
.down {
position: fixed;
}

i created a functional component to Class components.
<pre>
<code>
class ScrollButton extends React.Component {
onClick() {
window.scrollTo({
top: this.props.scrollTo,
behavior: 'smooth',
});
}
render() {
return (
<div className="down" style={{ top: `${this.props.top}px` }}>
<div className="down-text">Scroll to {this.props.scrollTo}
<button onClick={this.onClick.bind(this)}> ❯</button>
</div>
</div>
);
}
}
const App = () => (
<div className="container">
<ScrollButton scrollTo={500} top={50} />
<ScrollButton scrollTo={1000} top={100} />
<ScrollButton scrollTo={2000} top={200} />
</div>
);
</code>
</pre>

Related

how to change only current component style on hover

I have a requirement where I need to highlight the component on hover
I have two styles defined baseStyle and highlight
<div style={{ background: '#fff' }}>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
</div>
Expected Output:
on hovering any of the component only that component must be highlighted(i.e just need to add highlight css class to it).
but right now all the component is getting highlighted because of toolStyle state. can anyone help me on this by giving some logic.
Here is an example
you can create a small component with the highlight effect
and use it component any number of times and from anywhere
(As I said in comments )
https://codesandbox.io/s/laughing-mclaren-4i8en?file=/src/highlight.js
child.js
import { useState } from "react";
const baseStyle = { color: "black", fontSize: 14 };
const highlight = { color: "red" };
export default function Highlight({ text }) {
const [toolStyle, setToolStyle] = useState(baseStyle);
return (
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={(e) => setToolStyle(baseStyle)}
style={toolStyle}
>
{text}
</div>
);
}
parent.js
import Highlight from "./highlight";
import "./styles.css";
export default function App() {
return (
<div>
<Highlight text="text 1" />
<Highlight text="text 2" />
<Highlight text="text 3" />
</div>
);
}
This is the best way to implement this with code reusability and
less of code duplication
You can do something like this:
export default function App() {
let [hovered, setHovered] = React.useState({ div1: false, div2: false });
return (
<div>
<div
className={hovered.div1 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div1: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div1: false }))}
>
Hello
</div>
<div
className={hovered.div2 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div2: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div2: false }))}
>
Hello
</div>
</div>
);
}
You can move your styles to CSS file and avoid extra complexity:
App.js
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCoffee } from "#fortawesome/free-solid-svg-icons";
import "./App.css";
function App() {
return (
<div className="wrapper">
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
</div>
);
}
export default App;
App.css
.wrapper {
background: #fff;
}
.wrapper > div {
color: red;
font-size: 20px;
}
.wrapper > div:hover {
color: green;
cursor: pointer;
}

my .length method returns 0 when i has 9 divs in reactjs

const boxes = {
height: 220,
width: 220,
backgroundColor: 'red',
borderRadius: '25%',
};
const main = {
display: 'grid',
gridTemplateColumns: 'auto auto auto',
gridGap: '20px',
justifyContent: 'center',
marginTop: '20px',
};
const box = document.querySelectorAll('.boxes');
console.log(box.length);
class Easy extends React.Component {
render() {
return (
<div className="easy-game">
<div className="Easy-main" style={main}>
<div style={boxes} className="boxes" />
<div style={boxes} className="boxes" />
<div style={boxes} className="boxes" />
</div>
</div>
);
}
}
export default Easy;
This is my Code and my .length method gives 0 in return while there are 3 divs using the same class I am starting in react so I can be wrong somewhere
Your code runs before render, so there will be no element rendered
Move it inside a componentDidMount which run after the initial render:
class Easy extends React.Component {
componentDidMount() {
const box = document.querySelectorAll('.boxes'); //<-- Move it here
console.log(box.length);
}
render() {
return (
<div className="easy-game">
<div className="Easy-main" style={main}>
<div style={boxes} className="boxes" />
<div style={boxes} className="boxes" />
<div style={boxes} className="boxes" />
</div>
</div>
);
}
}

How do I use React Modal with a map function?

I'm mapping through data, I want to click on an image and have a modal popup with the data.title and data.info. Each modal is only showing the last data from my array. I've read that all the modals are popping up together and I'm only seeing the last one but I don't quite understand how to solve the problem, particularly with function components in React. TIA
export default function SomeComponent
const [modalIsOpen, setModalIsOpen] =
useState(false);
const customStyles = {
content: {
top: '35%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
width: '60%',
transform: 'translate(-40%, -10%)',
},
}
return (
<div className="container">
{ somedata.map((data) =>
(<div className='item' key={data.id} >
<img src={data.img} alt='' onClick={()=> setModalIsOpen(true)} />
<Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)} style={customStyles}>
<h1>{data.title</h1>
<p>{data.content</p>
<div>
<button onClick={() => setModalIsOpen(false)}>X</button>
</div>
</Modal>
</div>))}
</div>
</div>
);}
You should use only one instance of Modal component and pass on the data of the clicked image to it using a state. Each time you click on an image, the data for modal should be updated with the data of the clicked image. See the example below. I've modified your code to make it work.
export default function SomeComponent() {
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const customStyles = {
content: {
top: '35%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
width: '60%',
transform: 'translate(-40%, -10%)',
},
}
return (
<>
<div className="container">
{somedata.map(data => (
<div className='item' key={data.id} >
<img
src={data.img}
alt=''
onClick={()=> {
setModalData(data);
setModalIsOpen(true);
}
/>
</div>
))}
</div>
<Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)} style={customStyles}>
<h1>{modalData.title}</h1>
<p>{modalData.content}</p>
<div>
<button onClick={() => setModalIsOpen(false)}>X</button>
</div>
</Modal>
</>
)
}

React InfiniteScroll in a scrollable component on the page

I am trying to build an infinite scroll in a div with a fixed height and a scroll attached to it, so my goal is for the window not to move but a component within to have a scroll and the items within to be added infinatly.
this is what i have so far:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import InfiniteScroll from "react-infinite-scroll-component";
const style = {
height: 18,
border: "1px solid green",
margin: 6,
padding: 8
};
const DoseListCardBody = () => {
const [items, setItems] = useState(Array.from({ length: 20 }));
const fetchMoreData = () => {
setItems(items.concat(Array.from({ length: 10 })));
};
return (
<div style={{ height: "100%", overflowY: "scroll" }}>
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={items.length < 200}
loader={<h4>Loading...</h4>}
>
{items.map((i, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
);
};
ReactDOM.render(
<div style={{ height: "35rem", background: "black" }}>
<div style={{ height: "30rem", background: "white" }}>
<DoseListCardBody />
</div>
</div>,
document.getElementById("root")
);
everything works fine if i change
ReactDOM.render(
<div style={{ height: "35rem", background: "black" }}>
<div style={{ height: "30rem", background: "white" }}>
<DoseListCardBody />
</div>
</div>,
document.getElementById("root")
);
to
ReactDOM.render(
<DoseListCardBody />,
document.getElementById("root")
);
I think this is because it is using the scroll of the window not the component.
How do i get InfiniteScroll to use the parent component or a component with a scroll that I specify.
I appologise for the bad terminology, i dont usualy develop web pages.
ok got it!
one must use scrollableTarget as a prop in the InfiniteScroll and specify the ID of the compnent that has the scrollbar.
example:
const DoseListCardBody = () => {
const [items, setItems] = useState(Array.from({ length: 20 }));
const fetchMoreData = () => {
setItems(items.concat(Array.from({ length: 10 })));
};
return (
<div id="scrollableDiv" style={{ height: "100%", overflowY: "scroll" }}>
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={items.length < 200}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{items.map((i, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
);
};
notice the addition of 'id="scrollableDiv"' and 'scrollableTarget="scrollableDiv"'.

ReactJS ReactCSSTransitionGroup why does it work one component but not another?

Trying to figure out why this ReactCSSTransitionGroup animation works:
class SlideExample extends React.Component{
constructor(props) {
super(props);
this.state = { visible: false };
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({ visible: ! this.state.visible });
}
render() {
return <div>
<button onClick={this.handleClick}>{this.state.visible ? 'Slide up' : 'Slide down'}</button>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}>
{
this.state.visible
? <div className='panel'>
<ul className="project-list">
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</div>
: null
}
</ReactCSSTransitionGroup>
</div>
}
}
const ProjectList = (props) => {
return(
<div className="ProjectList">
<SlideExample />
</div>
);
}
But not like this:
class App extends Component {
constructor() {
super();
this.state = {
_isProjectNavOpen: true,
}
}
_toggleProjectNav() {
this.setState(prevState => ({
_isProjectNavOpen: !prevState._isProjectNavOpen,
}));
}
render() {
return(
<div className="App">
<Router>
<div className="main-content">
<Route path="/projects" component={(props, state, params) =>
<ProjectList
_toggleProjectNav={this._toggleProjectNav}
_isProjectNavOpen={this.state._isProjectNavOpen}
{...props} />} />
</div>
</Router>
</div>
);
}
}
const ProjectList = (props) => {
return(
<div className="ProjectList">
<div className="center title" onClick={props._toggleProjectNav} id="Menu">Menu</div>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}>
{
props._isProjectNavOpen
? <div className='panel'>
<ul className="project-list">
<li>xx one</li>
<li>xx two</li>
<li>xx three</li>
</ul>
</div>
: null
}
</ReactCSSTransitionGroup>
</div>
);
}
The CSS:
.panel {
width: 200px;
height: 100px;
background: green;
margin-top: 10px;
}
.example-enter {
height: 0px;
}
.example-enter.example-enter-active {
height: 100px;
-webkit-transition: height .3s ease;
}
.example-leave.example-leave-active {
height: 0px;
-webkit-transition: height .3s ease;
}
_toggleProjectNav is a prop passed down from a parent component that toggles the _isProjectNavOpen state true/false; it works in that the panel does hide/show, but without the animation... does it have to do with the state being passed from the parent? Trying to understand how ReactCSSTransitionGroup works.
Thanks!
This code works for me. In this case this is not a ReactCSSTransitionGroup issue. The issue is most probably related to the CSS. Pay attention, some browsers require initial height value before the transition. So you need something like this:
.example-leave {
height: 100px;
}

Resources