React-images gallery - reactjs

I am trying to build an image gallery with React-images(https://github.com/jossmac/react-images).
Here is my code so far.
https://codesandbox.io/s/gallant-yalow-7srs6
Here I am trying to achieve two things:
Implement the modal and the modal will open with current select image from the base gallery.
Change the "of" inside active view of total view on footer. i.e. currently its "1 of 4" so I need this like "1 / 4"
Could anyone please help me? I am kind of lost :(
Thanks in advance.

So I was able to achieve your requirement,
Working example : https://codesandbox.io/s/xenodochial-dawn-scjsv
And here is the code:
class gall extends React.Component {
state = { modalIsOpen: false, currentIndex: 0 };
toggleModal = () => {
this.setState(state => ({ modalIsOpen: !state.modalIsOpen }));
};
onImageChange = (index) => {
console.log(index)
this.setState(state => ({ currentIndex: index }));
};
render() {
const { modalIsOpen } = this.state;
const CustomModalFooter = ({ currentIndex, views }) => {
const activeView = currentIndex + 1;
const totalViews = views.length;
if (!activeView || !totalViews) return null;
return (
<span class="react-images__footer__count css-w6xjhe css-1ycyyax">
{activeView} / {totalViews}
</span>
);
};
return (
<>
<button
type="button"
className="btn-fullScreen"
onClick={this.toggleModal}
>
Open Modal
</button>
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleModal}>
<Carousel
currentIndex={this.state.currentIndex}
components={{ FooterCount: CustomModalFooter }}
views={images}
/>
</Modal>
) : null}
</ModalGateway>
<Carousel
onClick={this.onImageClick}
trackProps={{onViewChange:(index) => this.onImageChange(index)}}
components={{ FooterCount: CustomModalFooter }}
views={images}
/>
</>
);
}
}
export default gall;

Related

Cannot read properties of undefined - reactjs

Please help. I am new to react and I'm trying to toggle an accordion by using state but I'm getting an error on the onClick portion. Cannot read properties of undefined (reading 'toggleAccordion'). I'm confused to what I should do.
Any help would be appreciated. Thank you!
export class Accordion extends Component {
constructor(props) {
super(props);
this.state = {
isActive: false
}
this.toggleAccordion = this.toggleAccordion.bind(this);
this.renderAccordion = this.renderAccordion.bind(this);
}
toggleAccordion = () => {
this.setState({ isActive: !this.state.isActive})
}
renderAccordion = () =>
{
const { items } = this.props;
const { isActive } = this.state;
const accordionItems = items.map(function(item) {
return (
<div>
<button className={styles.accordion} onClick={this.toggleAccordion()}>
{item.title}
<span style={{float: "right"}}>{isActive ? '-' : '+'}</span>
</button>
{isActive && <div className={styles.content} dangerouslySetInnerHTML={{__html: item.content}}></div>}
<br/><br/>
</div>
)
})
return (
{accordionItems}
)
}
render() {
return(
<React.Fragment>
{this.renderAccordion()}
</React.Fragment>
)
}
}
In React you need to provide a reference to the function in event handlers, instead of calling the function. Try (note the parenthesis) :
<button className={styles.accordion} onClick={() => this.toggleAccordion()}>
or
<button className={styles.accordion} onClick={this.toggleAccordion}>
instead of
<button className={styles.accordion} onClick={this.toggleAccordion()}>
See https://reactjs.org/docs/handling-events.html#gatsby-focus-wrapper for more details on how React handle events.

Remove a class clicking a button in reactjs

I set class active when i click on a div.
const setActive = () => {
setActiveColor("active");
};
I want to delete this class when i click on click here to deselect color button from App component. How to do this?
Demo: https://codesandbox.io/s/exciting-elbakyan-hi12l?file=/src/App.js:541-569
const setActive = (flag) => {
setActiveColor(flag ? "active": "");
};
And you can set active as:
setActive(true);
or inactive as:
setActive(false);
You can have a state variable in your class and based on your clicks you can change that variable to add or remove class
class Demo{
constructor(){
this.state={addClass:true}
}
render(){
return({
this.state.addClass?<div className="some-class">With class</div>
:<div>Without class</div>
})
}
}
// Or
class Demo{
constructor(){
this.state={addClass:true}
}
render(){
return(
<div className={this.state.addClass?"some-name":null}>Lorem</div>
)
}
}
One approach could be to move activeStateColor to the parent.
Then when you click on the setActive you pass the key as reference.
export const Shape = ({ text, k, active, setActiveColor }) => {
const [state, setState] = useState({ visible: false });
const showModal = k => {
setState({
visible: true
});
setActiveColor(k);
};
const handleOk = e => {
console.log(e);
setState({
visible: false
});
};
const handleCancel = e => {
setActiveColor("");
console.log(e);
setState({
visible: false
});
};
const setActive = k => {
setActiveColor(k);
};
return (
<div>
<div>
<Button type="primary" onClick={() => showModal(k)}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={state.visible}
onOk={handleOk}
onCancel={handleCancel}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</div>
<div>
<div
k={k}
className={active === k ? "active" : ""}
style={{ border: "1px solid" }}
onClick={() => setActive(k)}
>
{text}
</div>
</div>
</div>
);
};

Invalid hook call with useCallback in react

I have a problem, I tried to transform in a class this function from this example :
https://codesandbox.io/s/5vn3lvz2n4
But, I got an error. Here is the code :
import React, { Component, useCallback } from "react";
import Gallery from "react-photo-gallery";
import Carousel, { Modal, ModalGateway } from "react-images";
class Gallerie extends Component {
constructor(props){
super(props)
this.state = {
currentImage: 0,
setCurrentImage: 0,
viewerIsOpen: false,
setViewerIsOpen: false,
}
}
render(){
const openLightbox = useCallback((event, { photo, index }) => {
this.state.setCurrentImage(index);
this.state.setViewerIsOpen(true);
}, []);
const closeLightbox = () => {
this.state.setCurrentImage(0);
this.state.setViewerIsOpen(false);
};
return (
<div>
<Gallery photos={this.props.photos} onClick={() => openLightbox} />
<ModalGateway>
{this.state.viewerIsOpen ? (
<Modal onClose={() =>closeLightbox}>
<Carousel
currentIndex={this.state.currentImage}
views={this.props.photos.map(x => ({
...x,
srcset: x.srcSet,
caption: x.title
}))}
/>
</Modal>
) : null}
</ModalGateway>
</div>
);
}
}
export default Gallerie;
Here is the problem and what I got :
I don't exaclty know what the useCallBack does. If I just copy / paste the example, it works. The problem is that the variable "photos" is used as props cause it will be different for each user. So I need it into other components. If I use a function like the example, I can't use props...
Thanks for your help.
You're using a hook inside a class based component. First convert it to a functional component
const Gallerie = props =>{
const [state, setState] = useState({
currentImage: 0,
setCurrentImage: 0,
viewerIsOpen: false,
setViewerIsOpen: false,
})
const openLightbox = useCallback((event, { photo, index }) => {
setState({...state, setCurrentImage: index, setViewerIsOpen: true});
}, []);
const closeLightbox = () => {
setState({...state, setCurrentImage: 0,setViewerIsOpen: false })
};
return (
<div>
<Gallery photos={props.photos} onClick={() => openLightbox} />
<ModalGateway>
{state.viewerIsOpen ? (
<Modal onClose={() =>closeLightbox}>
<Carousel
currentIndex={state.currentImage}
views={props.photos.map(x => ({
...x,
srcset: x.srcSet,
caption: x.title
}))}
/>
</Modal>
) : null}
</ModalGateway>
</div>
);
}

How to use react-virtualized with dynamic list height

I am trying to implement react-virtualized into my project. I have a side panel with a list of subdivisions. I would like to have an accordion-like functionality when the user selects an item. When the page first loads it looks like it is working correctly.
However when I start to scroll down the list looks like this
and here is code
const mapStateToProps = state => ({
windowHeight: state.dimensions.windowHeight,
sbds: new Immutable.List(state.sbds.data),
sbd: state.sbd.data
})
#connect(mapStateToProps)
export default class SBD extends Component {
static propTypes = {
windowHeight: PropTypes.number,
sbds: PropTypes.instanceOf(Immutable.List),
sbd: PropTypes.object
}
constructor(props) {
super(props)
this.state = {
listHeight: props.windowHeight - 250,
listRowHeight: 60,
overscanRowCount: 10,
rowCount: props.sbds.size,
scrollToIndex: undefined,
collapse: true
}
}
componentWillUnmount() {
}
shouldComponentUpdate(nextProps, nextState) {
const {sbds} = this.props
if (shallowCompare(this, nextProps, nextState))
return true
else return stringify(sbds) !== stringify(nextProps.sbds)
}
_handleSelectRow = selected => {
sbdRequest(selected)
const obj = {[selected.id]: true}
this.setState(obj)
}
render() {
const {
listHeight,
listRowHeight,
overscanRowCount,
rowCount,
scrollToIndex
} = this.state
return (
<div>
<SearchGroup />
<Card className='border-0 mt-10 mb-0'>
<CardBlock className='p-0'>
<AutoSizer disableHeight>
{({width}) => (
<List
ref='List'
className=''
height={listHeight}
overscanRowCount={overscanRowCount}
rowCount={rowCount}
rowHeight={listRowHeight}
rowRenderer={this._rowRenderer}
scrollToIndex={scrollToIndex}
width={width}
/>
)}
</AutoSizer>
</CardBlock>
</Card>
</div>
)
}
_getDatum = index => {
const {sbds} = this.props
return sbds.get(index % sbds.size)
}
_rowRenderer = ({index}) => {
const {sbd} = this.props
const datum = this._getDatum(index)
return (
<span key={datum.id}>
<Button
type='button'
color='link'
block
onClick={() => this._handleSelectRow(datum)}>
{datum.name}
</Button>
<Collapse isOpen={this.state[datum.id]}>
<Card>
<CardBlock>
FOO BAR
</CardBlock>
</Card>
</Collapse>
</span>
)
}
}
You're not setting the style parameter (passed to your rowRenderer). This is the thing that absolutely positions rows. Without it, they'll all stack up in the top/left as you scroll.
https://bvaughn.github.io/forward-js-2017/#/32/1

React Redux add line-through on checkbox click

I am trying to add a line-through on after checking a checkbox. I'm using react and redux. The action and reducer works. I just need a way of adding this line-through when checked is true Please find the code i tried implementing this below. Thanks in advance.
/actions/items.js
export const CHECK_ITEM = "CHECK_ITEM"
export function checkItem(id) {
return {
type: CHECK_ITEM,
id
}
}
/reducers/items.js
case types.CHECK_ITEM:
return state.map((item) => {
if(item.id === action.id) {
return Object.assign({}, item,
{
checked: !item.checked
})
}
return item
})
/components/Editor.jsx
renderValue = () => {
const onDelete = this.props.onDelete
const onCheck = this.props.onCheck
return (
<div>
{onCheck ? this.renderCheckItem() : null}
<div onClick={this.props.onValueClick}>
<span className='value'>{this.props.value}</span>
{onDelete ? this.renderDelete() : null}
</div>
</div>
)
}
renderCheckItem = () => {
return (
<input
type="checkbox"
className='check-item checked'
defaultChecked={false}
onClick={this.props.onCheck}
/>
)
}
/components/Item.jsx
export default class Items extends React.Component {
render () {
const {items, onEdit, onDelete, onValueClick, onCheck, isEditing} = this.props
return (
<ul className="items">{items.map(item =>
<Item
className="item"
key={item.id}
id={item.id}>
<Editor
value={item.text}
onCheck={onCheck.bind(null, item.id)}
style={{textDecoration: item.checked ? 'line-through' : 'none'}}
/>
</Item>
)}</ul>
)
}
}
You need to connect your components to the redux store. Here's how to do it. In short you need something like:
export default connect(
state => {
return {items: state.items};
}
)(Items);
Where connect comes from react-redux.
I basically passed item.checked as item to my Editor component and used it like so
...
render() {
const {item, value, onEdit, onValueClick, isEditing, onCheck, ...props} = this.props
...
then in my Editor.jsx i did the following
/components/Editor.jsx
renderValue = () => {
const onDelete = this.props.onDelete
const onCheck = this.props.onCheck
const itemChecked = this.props.item
const isChecked = {textDecoration: itemChecked ? 'line-through' : 'none'}
return (
<div>
{onCheck ? this.renderCheckItem() : null}
<div onClick={this.props.onValueClick}>
<span style={isChecked} className='value'>{this.props.value}</span>
{onDelete && this.renderDelete()}
</div>
</div>
)
}
renderCheckItem = () => {
return (
<input
type="checkbox"
className='check-item'
defaultChecked={false}
onClick={this.props.onCheck}
/>
)
}
/components/Items.jsx
export default class Items extends React.Component {
render () {
...
return (
<ul className='items'>{items.map((item) =>
<Item
className='item'
key={item.id}
id={item.id}>
<Editor
item={item.checked}
isEditing={item.isEditing}
...

Resources