Carousel in React using Flickity - reactjs

Is it possible for this code to work in React? I tried to use the .js file provided, however it fails. Could you please give me some tips on how to create such carousel in React?
// external js: flickity.pkgd.js
/* external css: flickity.css */
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body { font-family: sans-serif; }
.gallery {
background: #EEE;
}
.gallery-cell {
width: 66%;
height: 200px;
margin-right: 10px;
background: #8C8;
counter-increment: gallery-cell;
}
/* cell number */
.gallery-cell:before {
display: block;
text-align: center;
content: counter(gallery-cell);
line-height: 200px;
font-size: 80px;
color: white;
}
<p><code>wrapAround: true</code></p>
<!-- Flickity HTML init -->
<div class="gallery js-flickity"
data-flickity-options='{ "wrapAround": true }'>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
</div>

this is how you would implement it in react :
import Flickity from 'react-flickity-component'
const flickityOptions = {
initialIndex: 2
}
function Carousel() {
return (
<Flickity
className={'carousel'} // default ''
elementType={'div'} // default 'div'
options={flickityOptions} // takes flickity options {}
disableImagesLoaded={false} // default false
reloadOnUpdate // default false
static // default false
>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
<div class="gallery-cell"></div>
</Flickity>
)
}

No need for a wrapper. You just need to install flickity as a dependency, and you can import it dynamically. Here's how to use Flickity in React or Next.js:
export default function Carousel() {
useEffect(() => {
initFlickity();
}, []);
const carousel = useRef(null);
async function initFlickity() {
if (typeof window !== 'undefined' && carousel.current) {
const Flickity = (await import('flickity')).default;
new Flickity(carousel.current, {
lazyLoad: true,
wrapAround: true,
autoPlay: true,
});
}
}
return (
<div ref={carousel} className="w-full h-[600px] sm:w-[560px] sm:h-auto mx-auto relative">
<div>
<img src="/images/slide-1.jpg" />
</div>
<div>
<img src="/images/slide-2.jpg" />
</div>
</div>
);
}
Make sure you set dimensions for your containing element.

Related

How can I do conditional rendering on a styled component?

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}>

How do I change the size of an element using useState?

I can maximize and minimize with the SIZE button. But if the user changes the size of the editor window manually, the code doesn't work. How can I fix it?
I think I have to change the useState to take a non-boolean value, but I don't know to what.
Here's the App.js code
import { useState } from 'react';
import Editor from './components/Editor';
function App() {
const [content, setContent] = useState("")
function handleChange(event) {
setContent(event.target.value)
}
const [editorSize, setEditorSize] = useState(true)
function toggleEditorSize() {
setEditorSize(prevState => !prevState)
}
return (
<div className="App">
<Editor handleChange={handleChange} toggleEditorSize={toggleEditorSize} editorSize={editorSize}/>
</div>
);
}
export default App;
Here's the Editor.js code
export default function Editor(props) {
return (
<div>
<div className="editor-header">
<p className="editor-title">Editor</p>
<button onClick={props.toggleEditorSize}>SIZE</button>
</div>
<textarea id="editor" className={props.editorSize ? "max": ""} onChange={props.handleChange} >
</textarea>
</div>
)
}
Here's the Index.css code
background-color: white;
color: black;
border: 2px solid black;
position: relative;
display: inline-block;
overflow: scroll;
border-top: none;
min-width: 500px;
min-height: 300px;
max-width: 500px;
max-height: 600px;
height: 300px;
}
#editor.max, #preview.max {
height: 600px;
}
Hear what's happening is you have render component to detect the changes happed. here everytime when you click button useEffect will run and check if editorSize is true or not. if it's then it will set "max" class name to state ( Size ) and then here
<textarea id="editor" className={Size} onChange={props.handleChange} >
</textarea>
className will be set. Well, this should work. if it doesn't works try adding important property to you css. like this,
#editor.max, #preview.max {
height: 600px !important;
}
Here's the Editor.js code
export default function Editor(props) {
const[Size, setSize] = useState("");
useEffect(()=>{
if(props.editorSize){
setSize("max")
} else {
setSize("")
}
},[props.editorSize]);
return (
<div>
<div className="editor-header">
<p className="editor-title">Editor</p>
<button onClick={props.toggleEditorSize}>SIZE</button>
</div>
<textarea id="editor" className={Size} onChange={props.handleChange} >
</textarea>
</div>
)
}

React do I need a hook for each component?

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.

list jsx not re-rendered on state change

The below code snipped includes a clear explanation of the issues.
The explanation will appear if you run the code snipped by clicking the button
The code triggering the problem is
[0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />)
{this.state.src[i]} does not trigger the re-rendering of the jsx when the state is updated
const host = 'https://s3.eu-central-1.amazonaws.com/moviedatabase1/'
const noStarIcon = host + 'no_star.png'
const StarIcon = host + 'star.png'
class Feedback extends React.Component {
constructor(props){
super(props);
this.state = { src: [noStarIcon, noStarIcon, noStarIcon], text: "" }
this.changeIcon = this.changeIcon.bind(this)
this.list = [0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />)
}
changeIcon(){
this.setState({text: this.state.text + " state updated!"})
this.setState({src: [StarIcon, StarIcon, StarIcon]})
}
render() {
return (
<React.Fragment>
<p id="console">{this.state.text}</p>
<div class="box">{this.list}</div>
<div class="box box-blue flex-box">
<p>If I use the normal <b>jsx</b> tag, <b>setState</b> will trigger re-rendering of the <b>jsx</b> element</p> and the star will become yellow!
</div>
<div class="box">
<Star changeIcon={this.changeIcon} src={this.state.src[2]} key={2} id={2}/>
</div>
</React.Fragment>
);
}
}
class Star extends React.Component {
render() {
return <img src={this.props.src} onClick={this.props.changeIcon} style={this.props.style} id={this.props.id} />;
}
}
ReactDOM.render(
<Feedback />,
document.getElementById("react")
);
.box {
margin: 2vh 2vw;
color: white;
}
.box-blue {
border: solid 2px red;
background-color: blue;
border: solid 1px red;
margin: 2vh 2vw;
padding: 2vh 2vw;
color: white;
}
.flex-box {
display: flex;
flex-direction: column;
justify-content: space-around;
}
<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>
<div class="box box-blue flex-box">
<p>The two stars below are multiple <b>Components</b> rendered using the Javascript <b>.map</b> function, which saves an array of two <b>Star</b> components.</p>
<p>If you click on this two stars, the function <b>changeIcon</b> is called and updates the <b>state</b>, but the <b>jsx</b> is not re-rendered</p>
</div>
<div id="react"></div>
<hr>
<p>Credits for the icons</p>
<div>Icons made by Smashicons from www.flaticon.com is licensed by CC 3.0 BY</div>
It is because you are setting up your this.list in your constructor. Calling this.setState will not call your constructor again so it won't update it. It only triggers lifecycle events (such as render). See below.
const host = 'https://s3.eu-central-1.amazonaws.com/moviedatabase1/'
const noStarIcon = host + 'no_star.png'
const StarIcon = host + 'star.png'
class Feedback extends React.Component {
constructor(props){
super(props);
this.state = { src: [noStarIcon, noStarIcon, noStarIcon], text: "" }
this.changeIcon = this.changeIcon.bind(this)
}
changeIcon(){
this.setState({text: this.state.text + " state updated!"})
this.setState({src: [StarIcon, StarIcon, StarIcon]})
}
render() {
return (
<React.Fragment>
<p id="console">{this.state.text}</p>
<div class="box">{[0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />) }</div>
<div class="box box-blue flex-box">
<p>If I use the normal <b>jsx</b> tag, <b>setState</b> will trigger re-rendering of the <b>jsx</b> element</p> and the star will become yellow!
</div>
<div class="box">
<Star changeIcon={this.changeIcon} src={this.state.src[2]} key={2} id={2}/>
</div>
</React.Fragment>
);
}
}
class Star extends React.Component {
render() {
return <img src={this.props.src} onClick={this.props.changeIcon} style={this.props.style} id={this.props.id} />;
}
}
ReactDOM.render(
<Feedback />,
document.getElementById("react")
);
.box {
margin: 2vh 2vw;
color: white;
}
.box-blue {
border: solid 2px red;
background-color: blue;
border: solid 1px red;
margin: 2vh 2vw;
padding: 2vh 2vw;
color: white;
}
.flex-box {
display: flex;
flex-direction: column;
justify-content: space-around;
}
<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>
<div class="box box-blue flex-box">
<p>The two stars below are multiple <b>Components</b> rendered using the Javascript <b>.map</b> function, which saves an array of two <b>Star</b> components.</p>
<p>If you click on this two stars, the function <b>changeIcon</b> is called and updates the <b>state</b>, but the <b>jsx</b> is not re-rendered</p>
</div>
<div id="react"></div>
<hr>
<p>Credits for the icons</p>
<div>Icons made by Smashicons from www.flaticon.com is licensed by CC 3.0 BY</div>

How to open a particular accordion based click event in reactjs and autoclose remaining accordion?

I want to open a particular Section on clicking on that. How to do that by using click event? And also auto close the remaining accordion if I click on another accordion. Here is my code.
Accordion Component
import React, { Component } from 'react';
import Section from './section';
class Accordion extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
open: false,
headingClassName: 'accordion-heading',
className: 'accordion-content accordion-close',
Label: 'label-close',
icon: "+",
selectedItem: null,
};
}
handleClick = () => {
const open = this.state.open;
if (open) {
this.setState({
open: false,
className: "accordion-content accordion-close",
headingClassName: "accordion-heading",
Label: 'label-close',
icon: "+",
})
} else {
this.setState({
open: true,
className: "accordion-content accordion-open",
headingClassName: "accordion-heading clicked",
Label: 'label-open',
icon: "-",
})
}
}
render() {
return (
<div className="accordion-container">
<h1>Accordian Component</h1>
How to pass id as parameter in each section in onClick event to open
particular accordion and to autoclose remaining.
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="1">
<h3>One</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="2">
<h3>Two</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="3">
<h3>Three</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
</div>
);
}
}
export default Accordion;
Section Component
import React, { Component } from 'react';
class Section extends Component {
render() {
return (
<div className="parent-accordion">
{this.props.children}
</div>
);
}
}
export default Section;
CSS
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.accordion-container {
margin: auto;
width: 700px;
}
.accordion-container h1 {
color: #0000007a;
text-align: center;
font-family: sans-serif;
}
.parent-accordion {
width: 100%;
border: 1.5px solid #00000017;
}
.accordion-heading {
padding: 5px 5px;
background-color: #e2e2e254;
cursor: pointer;
text-transform: capitalize;
/* font-size: 17px; */
/* font-weight: 600; */
color: #2b2b41;
/* font-family: sans-serif; */
transition: background-color 1s;
}
.accordion-heading:hover {
background-color: #000000c7;
color: white;
First of all i've encompased a minimal (no css) example of how an accordion would behave on codesandbox, here.
This can be done multiple ways. In the example above the body of the tab is hidden with display:none if the tab is not active.Basically you iterate over your data in the render function and that's where you set your classes based on whatever flags you want (in your case isActive). You could render a Section for each tab and pass props to it.
The click handler updates your state with the id of the active tab.

Resources