I'm new with react and I'm trying to adapt my pagination to the design.
I'm not sure the react-paginate is the right one to use however I don't have much more expertise.
I managed to have something working but only with CSS, I don't like the hack approach.
is it possible to add Result found?
and page 1 of whatever?
my design should look like this:
But this is what I have at the moment:
And finally this is my react code:
<div className='paginate'>
<span className='result-found'>Result found</span>
<ReactPaginate
previousLabel="Back"
previousClassName="prev fa fa-caret-left"
nextLabel="Next"
nextClassName="next fa fa-caret-right"
breakLabel="..."
pageLinkClassName="page-link"
pageClassName="page"
breakClassName={""}
pageCount={total}
marginPagesDisplayed={1}
pageRangeDisplayed={4}
onPageChange={handlePageClick}
containerClassName="pagination"
subContainerClassName="pages pagination"
activeClassName="active"
/>
</div>
Here you go:
It is 90% CSS and 10% React. :D Edit the CSS for perfection. The code for the screenshot looks like this:
import { useEffect, useState } from "react";
import "./styles.css";
const PAGE_SIZE = 10;
export default function App() {
const [total, setTotal] = useState(42);
const [pageNo, setPageNo] = useState(0);
const maxPages = Math.ceil(total / PAGE_SIZE);
useEffect(() => {
// do your async call here
// set total
}, [pageNo]);
// take care of boundary condition like last and first pages
const onNext = () => pageNo < maxPages - 1 && setPageNo(pageNo + 1);
const onPrev = () => pageNo > 0 && setPageNo(pageNo - 1);
return (
<div className="App">
<div className="pagination-container">
<div className="pagination-left">
<span>{total} results found</span>
</div>
<div className="pagination-right">
<div className="pagination-current">
Page {pageNo + 1} of {maxPages}
</div>
<div className="pagination-buttons">
<div className="pagination-button-wrapper">
<button onClick={onPrev} className="pagination-button">
<
</button>
</div>
</div>
<div className="pagination-buttons">
<div className="pagination-button-wrapper">
<button onClick={onNext} className="pagination-button">
>
</button>
</div>
</div>
</div>
</div>
</div>
);
}
You can do usability enhancement by setting the buttons disabled={true} when the boundary condition reaches on first and last pages.
And the CSS is:
.pagination-container {
background-color: black;
display: flex;
justify-content: space-between;
padding: 1rem;
color: white;
}
.pagination-left {
display: flex;
align-items: center;
}
.pagination-right {
display: flex;
align-items: center;
}
.pagination-buttons {
display: flex;
margin-left: 0.5rem;
}
.pagination-buttons > * {
border: 1px solid white;
padding: 0.1rem 0.5rem;
}
.pagination-button {
background-color: transparent;
color: white;
border: 0;
}
Here also, you can edit CSS to match the exact style with arrows and buttons, and margins and paddings, and borders.
And a functional demo is here: https://codesandbox.io/s/zealous-ardinghelli-y4txu?file=/src/App.js
Larger Context: I assume you may want to reuse this component on multiple places. If so, you may want to extract out the logic into props. That means get rid of states and specialized logic (fetch data, in this case) to make it a stateless component by editing this component something like this:
interface Props {
onNext: () => void;
onPrev: () => void;
pageSize: number;
totalItems: number
}
export const PaginationBar = (props: Props) => {
// same code as above but no useEffect or useState
}
Now you have your own flexible pagination component. See here: https://codesandbox.io/s/eager-hermann-pjdt3?file=/src/App.js
You use it like this:
<Pagination
onNext={onNext}
onPrev={onPrev}
total={total}
pageNo={pageNo}
pageSize={10} />
Hope this helps!
React pagination come with minimum styling , anytime you can import demo css from github page
https://github.com/AdeleD/react-paginate/tree/master/demo/styles
in your component or
creating a styled component and customize your pagination all classes already include in your HTML like .active .first .last
or you can create custome styles for that class and append on your main.css
Related
I am using conditional rendering to make toggle function. But I think there is a problem with the method because I did conditional rendering on the styled component but it doesn't work. Can you tell me how to fix it? I'd appreciate it if you let me know thanks
my.jsx:
If I click on another image, the value of the profile becomes false, and if I click on the profile image, the value of the profile becomes true. And according to the value of the profile, I gave the value of the display by conditional rendering the tag whose className is IconWrap6True. But now, the display value of IconWrap6Trued keeps coming out as block, and 'none' is not applied. The cord is long, so I skipped the parts that I didn't need
import React, { useState } from 'react'
import styled from 'styled-components';
import defaultProfile from '../resources/images/img/defaultprofile.jpg'
const NavigationBarWrap1 = styled.div`
position: fixed;
flex-direction: column;
box-sizing: border-box;
display: flex;
flex-shrink: 0;
align-items: stretch;
.IconWrap6True {
${props => props.profile ? "block" : "none"};
box-sizing: border-box;
border-bottom-left-radius: 50%;
top: 50%;
border-top-right-radius: 50%;
left: 50%;
border: 2px solid rgb(38,38,38);
transform: translate(-50%,-50%);
}
`
function NavigationBar() {
//state
const[home, setHome] = useState(true);
const[profile,setProfile] = useState(true);
//true
const setTrueHome = () => {
setHome(true)
}
const setTrueProfile = () => {
setProfile(true)
}
//false
const setFalseHome = () => {
setHome(false)
}
const setFalseProfile = () => {
setProfile(false)
}
//handle
const forHome = (e) => {
setTrueHome();
setFalseProfile();
}
const forProfile = (e) => {
setFalseHome();
setTrueProfile();
}
return (
<NavigationBarWrap1>
<div className='IconWrap'>
<div className='IconWrap4'>
<div onClick={forHome} className='IconWrap5'>
<div>
<div className='IconWrap6'>
<div className='IconWrap7'>
{home===true?
<>
<img/>
</>:
<>
<img/>
</>}
</div>
</div>
</div>
</div>
</div>
</div>
<div className='IconWrap'>
<div className='IconWrap2'>
<div>
<div className='IconWrap6'>
<div profile={profile} className='IconWrap6True'/>
<div onclick={forProfile} className='IconWrap7'>
<img src={defaultProfile}/>
</div>
</div>
</div>
<div className='textWrap'>
<div className='textWrap2'>
<div className='textWrap3'>
프로필
</div>
</div>
</div>
</div>
</div>
</NavigationBarWrap1>
)
}
export default NavigationBar;
pass the profile prop to NavigationBarWrap1
<NavigationBarWrap1 profile={profile}>
I am using react, styled-components.
When state(visible) is set to true, DropMenu box1 and box2 will be displayed.
We want the ArrowDown icon to flip upward when state is true, and downward when false.
I also want to apply an animation when flipping it.
I want to add an animation like the Dropdown in the following site.
Reference site
code
import "./styles.css";
import styled from "styled-components";
import React, { useState, useCallback } from "react";
import { ArrowDown } from "./ArrowDown";
const Item = styled.div<{ active?: boolean }>`
height: 40px;
width: 300px;
padding: 0px 30px;
&:hover {
background: #fafbfb;
}
`;
const DropMenu = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
color: #899098;
width: 100%;
height: 100%;
font-size: 14px;
font-weight: bold;
gap: 12px;
:hover {
color: gray;
}
div {
display: flex;
align-items: center;
gap: 12px;
}
`;
const DropText = styled.div`
padding-left: 32px;
`;
export const App = () => {
const [visible, setVisible] = useState(false);
const handleDropVisibleChange = useCallback(() => {
setVisible((prevVisible) => !prevVisible);
}, [visible]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Item onClick={handleDropVisibleChange}>
<DropMenu>
<div>
<span>Menu</span>
</div>
<ArrowDown />
</DropMenu>
</Item>
{visible && (
<div style={{ transition: "all 0.5s ease" }}>
<Item>
<DropMenu>
<DropText>box1</DropText>
</DropMenu>
</Item>
<Item>
<DropMenu>
<DropText>box2</DropText>
</DropMenu>
</Item>
</div>
)}
</div>
);
};
export default App;
TLDR
Change your MenuItem component warpper to something like
const DropMenuWrapper = styled.div<{ visible: boolean }>`
transition: all 0.5s ease;
opacity: ${(props) => (props.visible ? 1 : 0)};
`;
replace the visibility switch mechanism with following
- {visible && (
- <div style={{ transition: "all 0.5s ease" }}>
+ <DropMenuWrapper visible={visible}>
similar action can be added to the arrow-down icon also with style
(The ArrowDown SVG icon must accept style if it is custom written component)
<ArrowDown
style={{
transition: "all 0.5s ease",
transform: `rotate(${visible ? 0 : "0.5turn"})`
}}
/>
Why this happened:
When a component (sub-component/element) is mounted in react, it starts a complete life cycle toward browser paint.
So it is must have the property which causes the element to animate, for example, I added the opacity transition to the example itself, forcing it to animate in the first look and in disappearing.
Although it comes with some performance cost of having unseen elements still in the dom (but not visible), making it bad for accessibility too, it is the simplest way to achieve this behavior.
Consider this example If you have an animated element, does it show the animation if you refresh the browser if the answer is yes, it will show animation in react too.
Another way of doing some animation in react.
Using third-party library react-transtion-group which is heavily used in lots of packages e.g. Material-UI.
In this case you can also trigger the end event and start to unmount the component as the animation disappears and end completely.
Using framer motion
If you want to take your understanding of what is needed for the transition when the component is unmounted and removed from aka dom, I highly encourage you to read the animation section of svelte docuementation
What I did, what might look stupid to more advanced developers was implement a simple check that would switch icons.
Note: This doesn't have an animation, though. It's just a simple switcharoo
define state in component
const [isOpen, setIsOpen] = useState(false);
Check whether icon is open or closed, if open, ExpandLessIcon, if closed ExpandMoreIcon.
<ExpandLessIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
) : (
<ExpandMoreIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
)}
The way it works is, once clicked, it'll just flip the true false state over and over, which in turn will change icons.
Problem Description
I have faced this issue multiple times and am not sure what is the best approach. Say I have 3+ components how can I have a state tracker for each of them? Do I need n useState() hooks for n components?
In this example, I want to change the image displayed with onMouseOver(). The way I did it, the hook state is applied to all the images, which is not what I desire to do.
Restrictions
I want to have eventually a custom drop-down menu with onClick() particular to the image folder. So in that sense, I need an individual state tracker for each component?
Code and Snippet
const openFolder = "https://i.postimg.cc/V6L7kBCV/folder-Open.png";
const closedFolder = "https://i.postimg.cc/hG0yn3fm/folder-Closed.png"
function App() {
const [image, setImage] = React.useState(closedFolder);
const handleMouseOver = () => {
setImage(openFolder);
}
const handleMouseLeave = () => {
setImage(closedFolder);
}
return (
<div className="window">
<div className="slider">
<div className="container">
{buildLatexFolder(image,handleMouseOver,handleMouseLeave)}
</div>
</div>
</div>
);
}
const buildLatexFolder = (image,handleMouseOver,handleMouseLeave) => {
const courseNames = [
'A', 'B', 'C', 'D', 'E', 'F'
//and many more other
]
var folders = courseNames.map((value, index) => {
return (
<div className="folderContainer">
<span>{value}</span>
<div onMouseEnter={() => {handleMouseOver()}} onMouseLeave={() => {handleMouseLeave()}}>
<img src={image} width="130"/>
</div>
</div>
);
});
return folders;
}
ReactDOM.render(<App />, document.querySelector("#app"));
.window {
width: 500px;
height: 130px;
display: flex;
align-items: center;
margin-left: auto;
margin-right: auto;
}
.slider {
border-radius: 0px 0px 16px 16px;
background-color: #1F1F1F;
color: #ffffff;
overflow: hidden;
float: right;
}
.container {
display: flex;
width: 700px;
height: 130px;
margin-top: 10px;
align-items: center;
text-align: center;
}
.folderElement {
margin-left: 12px;
margin-right: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
with JSFiddle here
What I Have Tried
Previously, when faced with this problem I would just make, say, 3 hooks for my 3 components and handle the logic this way. But now I have a large number of components and don't know what is the best approach.
I have searched online 'React Should I have a hook for each component', 'How many hooks to have for components', and so on and so forth but the search results are inaccurate with what I am trying to find, or for that matter my question is inaccurate. I don't know how to proceed.
Does anyone know how I can fix this issue?
You need to have component modularization in your application. Then you can have a single CourseFolder which can be used as a child component resides in your parent component which is App. Using map, you can view multiple child components having different courseDetails inside them.
Refer the following code-snippets I created to solve your issue.
App.js
import React from "react";
import CourseFolder from "./CourseFolder";
// import "./folderStyles.css"; /* kept the styles posted in the question */
const courseNames = [
"A",
"B",
"C",
"D",
"E",
"F",
//and many more other
];
function App() {
return (
<div className="window">
<div className="slider">
<div className="container">
{courseNames.map((value, index) => (
<CourseFolder value={value} key={index} />
))}
</div>
</div>
</div>
);
}
export default App;
Then create the child component as follows.
CourseFolder.js
import React from "react";
const openFolder = "https://i.postimg.cc/V6L7kBCV/folder-Open.png";
const closedFolder = "https://i.postimg.cc/hG0yn3fm/folder-Closed.png";
function CourseFolder(props) {
const { value, key } = props;
const [image, setImage] = React.useState(closedFolder);
const handleMouseOver = () => {
setImage(openFolder);
};
const handleMouseLeave = () => {
setImage(closedFolder);
};
return (
<div className="folderContainer" key={key}>
<span>{value}</span>
<div
onMouseEnter={() => {
handleMouseOver();
}}
onMouseLeave={() => {
handleMouseLeave();
}}
>
<img src={image} width="130" alt="alternative" />
</div>
</div>
);
}
export default CourseFolder;
Hope this would be helpful to solve your issue.
I'm trying to fetch some data inside useEffect and when the data is received I want to set a certain state with useState. Data correctly returns from the server. However this doesn't work. Here's the code:
const [sharingLink, setSharingLink] = React.useState(null);
React.useEffect(() => {
client.query({
query: queryGetReferalData
}).then(result => {
console.warn(result); // correct response
setSharingLink(result.data.referralsystem.shareUrl);
console.warn(sharingLink); // null
});
}, []);
Here's the whole component:
import React from 'react';
import styled from 'styled-components';
import { i18n } from 'Helpers';
import { Button } from './Button';
import { ButtonLink } from './ButtonLink';
import { Heading } from './Heading';
import { Input } from './Input';
import Copy from './icons/Copy';
import Facebook from './icons/Facebook';
import Twitter from './icons/Twitter';
import WhatsApp from './icons/WhatsApp';
import client from '#client/apollo';
import queryGetReferalData from './schemas/queryGetReferalData.graphql';
const Root = styled.div`
padding: 48px;
padding-top: 32px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0px 10px 30px rgba(27, 50, 85, 0.1);
border-radius: 4px;
background-color: #FFFFFF;
`;
const Pane = styled.div`
`;
const Row = styled.div`
display: flex;
& > * + * {
margin-left: 10px;
}
`;
export const Form = () => {
const [sharingLink, setSharingLink] = React.useState(null);
const facebookSharingLink =
sharingLink && `https://www.facebook.com/sharer/sharer.php?${encodeURIComponent(sharingLink)}`;
const twitterSharingLink =
sharingLink && `http://www.twitter.com/share?url=${encodeURIComponent(sharingLink)}`;
const whatsAppSharingLink =
sharingLink && `whatsapp://send?text=${encodeURIComponent(sharingLink)}`;
React.useEffect(() => {
client.query({
query: queryGetReferalData
}).then(result => {
console.warn(result);
setSharingLink(result.data.referralsystem.shareUrl);
console.warn(sharingLink);
});
}, []);
return (
<Root>
<Pane>
<Heading>
{ i18n._('Your invitational link') }
</Heading>
<Row>
<Input disabled={sharingLink === null} value={sharingLink} />
<Button icon={<Copy />}>
{ i18n._('COPY') }
</Button>
</Row>
</Pane>
<Pane>
<Heading>
{ i18n._('Or share via social') }
</Heading>
<Row>
<ButtonLink
backgroundColor='#5A79B5'
icon={<Facebook />}
href={facebookSharingLink}
>
{ i18n._('Facebook') }
</ButtonLink>
<ButtonLink
backgroundColor='#52A6DB'
icon={<Twitter />}
href={twitterSharingLink}
>
{ i18n._('Twitter') }
</ButtonLink>
<ButtonLink
backgroundColor='#0DC455'
icon={<WhatsApp />}
href={whatsAppSharingLink}
>
{ i18n._('WhatsApp') }
</ButtonLink>
</Row>
</Pane>
</Root>
);
};
The component also renders like sharingLink is null.
Why is this happening?
What do I do to make this work?
I had some code that was adding to the DOM in the parent component. When I remove it, everything works.
Adding to the DOM in the component, doesn't matter if it's into useEffect or not, somehow messes up hooks even though you add HTML to something completely unrelated to react I guess.
I had this structure:
<body>
<div id="page">
<div id="root">
<CustomReactElement />
</div>
</div>
<body>
The code inside CustomReactElement was adding markup to the 'page'. I changed the code from setting an innerHTML to appendChild() and everything worked.
I'm new to React, trying to integrate some animations. I'm using Gatsby.js framework.
const LeadHeading = styled(animated.h1)`
font-weight: bold;
font-size: 3rem;
font-family: ${props => props.theme.fontSecondary};
margin-bottom: 0;
line-height: 2.5rem;
color: #FFF3D8;
const IndexPage = ({menuOpen}) => {
const h1Animation = useSpring({
opacity: menuOpen ? '0' : '1'
})
return (
<>
<Layout>
<Section className="hero is-fullheight">
<div className="hero-body container is-flex">
<LeadHeading
style={h1Animation}
>
some heading
</LeadHeading>
</div>
</Section>
</Layout>
</>
)
}
export default IndexPage
The menu status is managed in the "layout" component via the useState hook.
const [menuOpen, setMenuOpen] = useState(false)
Basically, I just want to fadeout the h1 when the menu pops up, since it doesn't look good due to the transparency of the menu.
Appreciate your help.
const LeadHeading = styled(animated.h1)`
font-weight: bold;
font-size: 3rem;
font-family: ${props => props.theme.fontSecondary};
margin-bottom: 0;
line-height: 2.5rem;
color: #FFF3D8;
`
const IndexPage = ({menuOpen}) => {
const h1Animation = useSpring({
opacity: menuOpen ? '0' : '1'
})
return (
<>
<Layout>
<Section className="hero is-fullheight">
<div className="hero-body container is-flex">
<LeadHeading
style={h1Animation}
>
some heading....
</LeadHeading>
</div>
</Section>
</Layout>
</>
)
}
export default IndexPage
EDIT// The menu status is managed in the "layout" component via useState hook.
But it should be possible, to pass the data to "IndexPage" right?
Ok I thought I can skip the animated part in the render method, since I use it above in the styled component variable. (sry I forgot to mention that in my previous post).
Your approach was one of my first approaches but it didnt work.