Im using react-image-gallery: https://www.npmjs.com/package/react-image-gallery
Im trying to set a useState variable on onImageLoad, but its not working.
the docs say to use a callback, and I tried using a callback but I don't think I was doing it correctly for functional components.
Could someone show me how to create the proper callback to get the onImageLoad prop?
Docs say..... onImageLoad: Function, callback(event)
import React, { useEffect, useState} from "react";
import ImageGallery from 'react-image-gallery';
import "react-image-gallery/styles/css/image-gallery.css";
const Job = (props) => {
const {job} = props;
const [image, setImage] = useState([]);
const [showImages, setShowImages] = useState(false);
useEffect(() => {
async function onLoad() {
try {
const downloadedImage = await getImage(job.jobId);
setImage(downloadedImage);
} catch (e) {
alert(e);
}
}
onLoad();
}, []);
return (
{showImages ? (
<div style={{width: "95%"}}>
<ImageGallery items={image} onImageLoad={() => setShowImages(true)}/>
</div>
):(
<div>
<IonSpinner name="crescent" />
</div>
)}
);
Example given from package website
import React from 'react';
import ReactDOM from 'react-dom';
import ImageGallery from '../src/ImageGallery';
const PREFIX_URL = 'https://raw.githubusercontent.com/xiaolin/react-image-gallery/master/static/';
class App extends React.Component {
constructor() {
super();
this.state = {
showIndex: false,
showBullets: true,
infinite: true,
showThumbnails: true,
showFullscreenButton: true,
showGalleryFullscreenButton: true,
showPlayButton: true,
showGalleryPlayButton: true,
showNav: true,
isRTL: false,
slideDuration: 450,
slideInterval: 2000,
slideOnThumbnailOver: false,
thumbnailPosition: 'bottom',
showVideo: {},
};
this.images = [
{
thumbnail: `${PREFIX_URL}4v.jpg`,
original: `${PREFIX_URL}4v.jpg`,
embedUrl: 'https://www.youtube.com/embed/4pSzhZ76GdM?autoplay=1&showinfo=0',
description: 'Render custom slides within the gallery',
renderItem: this._renderVideo.bind(this)
},
{
original: `${PREFIX_URL}image_set_default.jpg`,
thumbnail: `${PREFIX_URL}image_set_thumb.jpg`,
imageSet: [
{
srcSet: `${PREFIX_URL}image_set_cropped.jpg`,
media : '(max-width: 1280px)',
},
{
srcSet: `${PREFIX_URL}image_set_default.jpg`,
media : '(min-width: 1280px)',
}
]
},
{
original: `${PREFIX_URL}1.jpg`,
thumbnail: `${PREFIX_URL}1t.jpg`,
originalClass: 'featured-slide',
thumbnailClass: 'featured-thumb',
description: 'Custom class for slides & thumbnails'
},
].concat(this._getStaticImages());
}
_onImageLoad(event) {
console.debug('loaded image', event.target.src);
}
render() {
return (
<section className='app'>
<ImageGallery
ref={i => this._imageGallery = i}
items={this.images}
onImageLoad={this._onImageLoad}
/>
</section>
);
}
}
ReactDOM.render(<App/>, document.getElementById('container'));
Related
Need working example of implementing server side filter and sort on each column in react AG-grid.
With below sample code - am not able to capture filter or sorting value to use it for server side request(api call).
<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>
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import PropTypes from 'prop-types';
import { AgGridReact} from 'ag-grid-react';
import 'ag-grid-enterprise';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
function createServerSideDatasource(rowData) {
return {
getRows(params) {
const { startRow, endRow, filterModel, sortModel } =
params.request;
params.successCallback(rowData, 500);
},
};
}
const AgGridComponent = props => {
const gridRef = useRef();
const { rowData, columnDefs } = props;
const gridStyle = useMemo(
() => ({ height: '100%', width: '100%' }),
[]
);
const defaultColDef = useMemo(
() => ({
filter: true,
floatingFilter: true,
sortable: true,
enableServerSideSorting: true,
enableServerSideFilter: true,
}),
[]
);
const onGridReady = useCallback(params => {
const columnToolPanel =
params.api.getToolPanelInstance('columns');
columnToolPanel.collapseColumnGroups();
params.api.closeToolPanel();
const datasource = createServerSideDatasource(rowData);
params.api.setServerSideDatasource(datasource);
}, []);
return (
<div style={containerStyle}>
<div style={gridStyle} className="ag-theme-alpine-dark">
<AgGridReact
ref={gridRef}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
// pagination
// paginationPageSize={20}
domLayout="autoHeight"
rowModelType="serverSide"
onGridReady={onGridReady}
/>
</div>
</div>
);
};
AgGridComponent.propTypes = {
rowData: PropTypes.array,
columnDefs: PropTypes.array,
};
AgGridComponent.defaultProps = {
rowData: [],
columnDefs: [],
};
export default AgGridCmp;
Don't need local filter or sort everything, need to be done through server side.
Not looking for infinite pagination, using traditional one only.
I am using React Testing Library for first time and it seems very confusing. I am stuck on the error since long. I will be very grateful if someone proposes a solution to this problem
Here is my testfile:
import React from 'react';
import { cleanup, fireEvent, screen } from '#testing-library/react';
import { act } from 'react-dom/test-utils';
import { render } from '../../../test-util';
import EmailEditor from '../../../../components/commonComponents/EmailInput/EmailChip';
const mockFn = jest.fn();
const props={
salutation: '',
signature: '',
emailBody: '',
onChangeEmailBody: () => { },
onFocus: () => { },
onBlur: () => { },
disabled: false,
showSalutation: true,
showSignature: true,
allowVariables: false,
showPersonalize: false,
customParams: [],
recommendImgSize: '',
autoFocus: false,
allowFonts: true
}
describe('Email Editor Test cases', () => {
afterEach(cleanup);
it('Determining the ', async () => {
act(() => {
render(<EmailEditor {...props} /> );
});
const OnclickElement = screen.getByText(/Select Personalization Parameter/i)
expect(OnclickElement).toBeInTheDocument();
});
it('should render the button', async () => {
act(() => {
render(<EmailEditor {...props} /> );
});
const OnclickElement = screen.getByTestId(/custom/i)
expect(OnclickElement).toBeInTheDocument();
});
Here are some of the elements which are associated in index.js
<Header style={{ fontSize: window.innerWidth > MOBILE_WIDTH ? '1.15vw' : 12.15 }}>Select Personalization Parameter</Header>
<CustomToolbar key="customToolbar" show={allowVariables && showPersonalize} uniqueKey={uniqueKey} recommendImgSize={recommendImgSize} allowFonts={allowFonts} data-testid = "custom"/>
Please help me with this.
The following Draftjs code is in class component. The plugins like CreateImage, Focus Plugin, and BlockDndPlugin are being imported from the DraftJS. I would be grateful if somebody can convert the class-based react components into Functional based react components...............................................................................................................................................................................................................................................................................................
import React, { Component } from 'react';
import { convertFromRaw, EditorState } from 'draft-js';
import Editor, { composeDecorators } from '#draft-js-plugins/editor';
import createImagePlugin from '#draft-js-plugins/image';
import createFocusPlugin from '#draft-js-plugins/focus';
import createBlockDndPlugin from '#draft-js-plugins/drag-n-drop';
import editorStyles from './editorStyles.module.css';
const focusPlugin = createFocusPlugin();
const blockDndPlugin = createBlockDndPlugin();
const decorator = composeDecorators(
focusPlugin.decorator,
blockDndPlugin.decorator
);
const imagePlugin = createImagePlugin({ decorator });
const plugins = [blockDndPlugin, focusPlugin, imagePlugin];
/* eslint-disable */
const initialState = {
entityMap: {
0: {
type: 'IMAGE',
mutability: 'IMMUTABLE',
data: {
src: '/images/canada-landscape-small.jpg',
},
},
},
blocks: [
{
key: '9gm3s',
text:
'You can have images in your text field which are draggable. Hover over the image press down your mouse button and drag it to another position inside the editor.',
type: 'unstyled',
depth: 0,
inlineStyleRanges: [],
entityRanges: [],
data: {},
},
{
key: 'ov7r',
text: ' ',
type: 'atomic',
depth: 0,
inlineStyleRanges: [],
entityRanges: [
{
offset: 0,
length: 1,
key: 0,
},
],
data: {},
},
{
key: 'e23a8',
text:
'You can checkout the alignment tool plugin documentation to see how to build a compatible block plugin …',
type: 'unstyled',
depth: 0,
inlineStyleRanges: [],
entityRanges: [],
data: {},
},
],
};
/* eslint-enable */
export default class CustomImageEditor extends Component {
state = {
editorState: EditorState.createWithContent(convertFromRaw(initialState)),
};
onChange = (editorState) => {
this.setState({
editorState,
});
};
focus = () => {
this.editor.focus();
};
render() {
return (
<div>
<div className={editorStyles.editor} onClick={this.focus}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
ref={(element) => {
this.editor = element;
}}
/>
</div>
</div>
);
}
}
You can use useState and useRef hooks in FC & Modify your component accordingly..
const CustomImageEditor = () => {
const [editorState, setEditorState] = useState(
EditorState.createWithContent(convertFromRaw(initialState))
);
const editor = useRef();
const onChange = (editorStates) => {
setEditorState(editorStates);
};
const focus = () => {
editor.current.focus();
};
return (
<div>
<div className={editorStyles.editor} onClick={focus}>
<Editor
editorState={editorState}
onChange={onChange}
plugins={plugins}
ref={editor}
/>
</div>
</div>
);
};
I am passing through props to my Buttons.jsx file. Each button would drop down a video. My problem is that when I click one button, all of the videos appear. I want it so that only that certain video that was clicked would show.
here is the link to repo
https://noahfarinas.github.io/stretching/
Thanks in advance!
Buttons.jsx
import { useState } from "react";
import ReactPlayer from "react-player";
export const Buttons = (props) => {
const { content } = props;
const [showVideo,setShowVideo] = useState(false);
const handleOnClick = () => setShowVideo(true);
return (
<div className="buttonContainer">
{content.map((item) => (
<div className="buttonSpace">
<button id="btn" onClick={handleOnClick}>{item.title}</button>
{showVideo ? <ReactPlayer url={item.embed} /> : null}
</div>
))}
</div>
);
};
export default Buttons;
**App.js**
import "./App.css";
import Search from "./Search";
import TitleView from "./TitleView";
import Buttons from "./Buttons";
function App() {
const TITLE = "Stretches";
const DATA = [
{
area: "upper-back",
video: "https://www.youtube.com/watch?v=bTn89EBKJdM",
},
{
area: "mid-back",
video: "https://www.youtube.com/watch?v=VnDuWC40egg",
},
{
area: "lower-back",
video: "https://www.youtube.com/watch?v=N-xqKx8oshs",
},
{
area: "hips",
video: "https://www.youtube.com/watch?v=nLuvQCTPrcY",
},
{
area: "calves",
video: "https://www.youtube.com/watch?v=37GHTaoknfw",
},
{
area: "chest",
video: "https://www.youtube.com/watch?v=NePr1XKRTLU",
},
{
area: "glute",
video: "https://www.youtube.com/watch?v=eRCpceBhcm0",
},
{
area: "foot",
video: "https://www.youtube.com/watch?v=AXSj_5pBAKw",
},
{
area: "forearm",
video: "https://www.youtube.com/watch?v=Ayhu7TzNGSQ",
},
{
area: "it band",
video: "https://www.youtube.com/watch?v=i6Psvd81Hyc",
},
{
area: "hamstring",
video: "https://www.youtube.com/watch?v=pJUwEBgxWoE",
},
{
area: "tricep",
video: "https://www.youtube.com/watch?v=SaZK9vlSmHI",
},
{
area: "lat",
video: "https://www.youtube.com/watch?v=6V5tSn9oEJg",
},
];
const BUTTONDATA = [
{
title: "back",
embed: "https://www.youtube.com/watch?v=buF1v8aiTvM",
},
{
title: "legs",
embed: "https://www.youtube.com/watch?v=UIRTPXj1Q1U",
},
{
title: "upper-body",
embed: "https://www.youtube.com/watch?v=Kpd9ik93Sxk",
},
{
title: "hips",
embed: "https://www.youtube.com/watch?v=j42sLnoMkrA",
},
];
return (
<div className="App">
<TitleView headline={TITLE} />
<Search placeholder="What hurts..." data={DATA} />
<Buttons content={BUTTONDATA} />
</div>
);
}
export default App;
The problem can be solved in two ways. One way is to have a map in app.js on the BUTTONDATA and render separate component for each item of the array. In this way each Button Component will have its own state and will show only its own contents upon button click.
The other way is to have a boolean property for each of array item in the BUTTONDATA. and then you can modify your component in the following way:
Button.js
import { useEffect, useState } from "react";
import ReactPlayer from "react-player";
const Buttons = (props) => {
const { content } = props;
const [visibilityChanged, setVisibiltyChanged] = useState(false);
useEffect(() => {}, [visibilityChanged]);
const handleOnClick = (index) => () => {
content[index].isVisible = !content[index].isVisible;
setVisibiltyChanged(!visibilityChanged);
};
return (
<div className="buttonContainer">
{content.map((item, index) => (
<div className="buttonSpace" key={index}>
<button id="btn" onClick={handleOnClick(index)}>
{item.title}
</button>
{item.isVisible ? <ReactPlayer url={item.embed} /> : null}
</div>
))}
</div>
);
};
export default Buttons;
and in app.js will have the following changes:
App.js
const BUTTONDATA = [
{
title: "back",
embed: "https://www.youtube.com/watch?v=buF1v8aiTvM",
isVisible: false
},
{
title: "legs",
embed: "https://www.youtube.com/watch?v=UIRTPXj1Q1U",
isVisible: false
},
{
title: "upper-body",
embed: "https://www.youtube.com/watch?v=Kpd9ik93Sxk",
isVisible: false
},
{
title: "hips",
embed: "https://www.youtube.com/watch?v=j42sLnoMkrA",
isVisible: false
}
];
Here is the code sandbox I created to toggle videos on button click.
I am building rich text editor using react with typescript But I am getting error which I have attached in the snapshot and also I have pasted my EditorState.tsx code
So could you please let me know why I am getting this error
import React, {Component} from 'react';
import { render } from 'react-dom';
import {EditorState} from "draft-js";
import {Editor} from "react-draft-wysiwyg";
type MyProps = {
}
type MyState = {
editorState:any
}
class EditorContainer extends Component<MyProps,MyState>{
constructor(props:MyProps){
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
}
onEditorStateChange: Function = (editorState:any) => {
// console.log(editorState)
this.setState({
editorState,
});
};
render(){
const { editorState } = this.state;
return <div className='editor'>
<Editor
editorState={editorState}
onEditorStateChange={this.onEditorStateChange}
toolbar={{
inline: { inDropdown: true },
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true },
// image: { uploadCallback: uploadImageCallBack, alt: { present: true, mandatory: true } },
}}
/>
</div>
}
}
onEditorStateChange: Function = (editorState:any) => {
You've given this the type Function, which means it could be literally any function. Then when you try to pass the function into the editor, typescript is pointing out that only specific functions are allowed, not any function.
Instead, do:
onEditorStateChange = (editorState: EditorState) => {
this.setState({
editorState,
});
};