Reactjs: How to move dialog to top of the screen on click - javascript

When I clicked over a draggable dialog, I want to move to the top of the screen.
I have tried with scrollTo(0, 0), but this seems to not doing anything over my dialog box. Any help over it how can I able to move this dialog box.
Many Thanks in advance.
I am following this Move draggable objects to top of the screen or Div? example but need this to be with on click.
class Homepage extends Component {
constructor(props) {
super(props);
this.state = {
Pending:[],
cancelled:[],
}
this.myRef = React.createRef();
}
componentDidMount() {
this.myRef.current.scrollTo(0, 0);
}
componentDidUpdate(prevProps, prevState) {
if(!prevProps.isModerator){
if(prevProps.Permission === Permission &&
this.props.Permission === Requested){
}
}
}
render() {
const {allowRequest, classes} = this.props;
const { Pending} = this.state;
return (
<>
{Pending.map((user, index) => {
return <Draggable bounds="parent" key={user.id} ref={this.myRef}>
<div className={classes["share-request-content"]} >
<Paper className="alert-container" square={true}>
<DialogTitle id="alert-title">
{/* Title here */}
</DialogTitle>
<DialogContent>
{/* Content here */}
</DialogContent>
<DialogActions className="dialog-action">
<Button autoFocus color="primary" onClick={() => allowRequest(user.id)}>
"Allow"
</Button>
</DialogActions>
</Paper>
</div>
</Draggable>
})
}
</>
)
}
}
Homepage.propTypes = {
Permission: PropTypes.string,
isModerator: PropTypes.bool.isRequired,
Pending: PropTypes.array,
cancelled: PropTypes.array,
};
export default withStyles(styles)(injectIntl(Homepage))

Use the position={{x:0, y:0}} property to manually control the position of the dialog.
You can find the references here: https://github.com/STRML/react-draggable

Related

Reactjs: Dialog open is not working on button click

I am trying to open and close a dialog on a button click from another page/component.
But it is not working on clicking the button.
Any sugegstion what I am missing and doing wrong here with handeling modal.
Thanks in advance.
//TestComponent
class TestConnectDialog extends React.Component {
render() {
const {isOpen, onOk} = this.props;
return (
<Dialog
isopen={this.props.isopen}
onClose={this.props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleClose} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
// Home page
import TestConnectDialog from './TestConnectDialog';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
this.handleTestConnectClick = this.handleTestConnectClick.bind(this);
//this.handleCloseDialog = this.handleCloseDialog.bind(this);
}
handleTestConnectClick= () =>{
this.setState({ isOpen: true });
}
render() {
const {isOpen, onOk} = this.props;
return (
<div className="section">
<Button className="connect-test-button"
onClick={this.handleTestConnectClick}>
Test
</Button>
<TestConnectDialog isOpen={this.state.isOpen} />
</div>
);
}
};
export default HomePage;
Your prop name is spelled incorrectly, it should be this.props.isOpen also a quick little tip, it is possible to use just one function for opening/closing the modal.
Something like this will work:
handleTestConnectClick = () => {
this.setState(prevState => ({
...prevState,
isOpen: !prevState.isOpen
}));
}
here we use our previous state and with the ! operator we switch from true to false and vice versa
Update 2.0:
After taking a closer look at the Material UI documentation, I noticed that your dialog prop for setting the modal visibility is wrong. It should be open instead of isOpen.
import TestConnectDialog from './TestConnectDialog';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
//this.handleTestConnectClick = this.handleTestConnectClick.bind(this);
//this.handleCloseDialog = this.handleCloseDialog.bind(this);
// when using arrow functions you don't need to bind the this keyword
}
handleTestConnectClick = () => {
this.setState(prevState => ({
...prevState,
isOpen: !prevState.isOpen
}));
}
render() {
return (
<div className="section">
<Button className="connect-test-button"
// onClick={this.handleTestConnectClick}>
// change the onClick to the one below
onClick={ () => this.handleTestConnectClick() }
Test
</Button>
<TestConnectDialog isOpen={this.state.isOpen} handleTestConnectClick={this.handleTestConnectClick}/>
</div>
);
}
};
export default HomePage;
In TestConnectDialog component:
class TestConnectDialog extends React.Component {
render() {
return (
<Dialog
open={this.props.isOpen}
onClose={this.props.handleTestConnectClick}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleTestConnectClick} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
You're passing the props <TestConnectDialog isOpen={this.state.isOpen} /> but trying to read it with isopen={this.props.isopen}.
Change your code to this: isopen={this.props.isOpen}
Update TestComponent component as given
class TestConnectDialog extends React.Component {
render() {
const {isOpen, onOk} = this.props;
return (
<Dialog
isopen={isOpen}
onClose={this.props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Test
</DialogContentText>
</DialogContent>
<DialogActions className="dialog-action">
<Button onClick={this.props.handleClose} className="primary-button">
Ok
</Button>
</DialogActions>
</Dialog>
);
}
};
export default TestConnectDialog;
In the homepage component why is isOpen destructured from the prop and initialised in state. You have to use one, using both is confusing, you are working with that on the state but passing the one from the prop

How to call child component method from parent

In my Reactjs app, I need to have a parent component (a wizard) named Wizard.js and a number of child components (steps of the wizard) named PrimaryForm.js, SecondaryForm.js etc. They all are Class based components with some local validation functions.
Previous and Next buttons to advance the steps, reside in the Wizard.js.
To advance the next step of the wizard, I'm trying to call a method from PrimaryForm. I checked similar questions in Stackoverflow; tried using ref or forwardRef, but I could not make it work. I currently receive "TypeError: Cannot read property 'handleCheckServer' of null" error.
Below are my parent and child classes. Any help about what I would be doing wrong is appreciated.
Wizard.js:
import React, { Component } from 'react';
...
const getSteps = () => {
return [
'Info',
'Source Details',
'Target Details',
'Configuration'
];
}
class Wizard extends Component {
constructor(props) {
super(props);
this.firstRef = React.createRef();
this.handleNext = this.handleNext.bind(this);
this.state = {
activeStep: 1,
}
}
componentDidMount() {}
handleNext = () => {
if (this.state.activeStep === 1) {
this.firstRef.current.handleCheckServer(); <<<<<<<<<<<<<<<<< This is where I try to call child method
}
this.setState(state => ({
activeStep: state.activeStep + 1,
}));
};
handleBack = () => {
this.setState(state => ({
activeStep: state.activeStep - 1,
}));
};
handleReset = () => {
this.setState({
activeStep: 0,
});
};
render() {
const steps = getSteps();
const currentPath = this.props.location.pathname;
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<Topbar currentPath={currentPath} />
<div className={classes.root}>
<Grid container spacing={2} justify="center" direction="row">
<Grid container spacing={2} className={classes.grid} justify="center" direction="row">
<Grid item xs={12}>
<div className={classes.topBar}>
<div className={classes.block}>
<Typography variant="h6" gutterBottom>Wizard</Typography>
<Typography variant="body1">Follow the wizard steps to create a configuration.</Typography>
</div>
</div>
</Grid>
</Grid>
<Grid container spacing={2} alignItems="center" justify="center" className={classes.grid}>
<Grid item xs={12}>
<div className={classes.stepContainer}>
<div className={classes.bigContainer}>
<Stepper classes={{ root: classes.stepper }} activeStep={this.state.activeStep} alternativeLabel>
{steps.map(label => {
return (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
);
})}
</Stepper>
</div>
<PrimaryForm ref={this.firstRef} />
</div>
</Grid>
</Grid>
<Grid container spacing={2} className={classes.grid}>
<Grid item xs={12}>
<div className={classes.flexBar}>
<Tooltip title="Back to previous step">
<div>
<Button variant="contained"
disabled={(this.state.activeStep === 0)}
className={classes.actionButton}
onClick={this.handleBack}
size='large'>
<BackIcon className={classes.rightIcon} />Back
</Button>
</div>
</Tooltip>
<Tooltip title="Proceed the next step">
<div>
<Button
variant="contained" className={classes.actionButton}
color="primary"
size='large'
disabled={!(!this.state.isFormValid || this.state.isTestWaiting)}
onClick={this.handleNext}>
<ForwardIcon className={this.props.classes.rightIcon}/>Next</Button>
</div>
</Tooltip>
<Tooltip title="Cancel creating new configuration">
<Button variant="contained" color="default" className={classes.actionButton}
component={Link} to={'/configs'} style={{ marginLeft: 'auto' }}>
<CancelIcon className={classes.rightIcon} />Cancel
</Button>
</Tooltip>
</div>
</Grid>
</Grid>
</Grid>
</div>
</React.Fragment>
)
}
}
export default withRouter(withStyles(styles)(Wizard));
PrimaryForm.js:
import React, { Component } from 'react';
...
class PrimaryForm extends Component {
constructor(props) {
super(props);
this.handleCheckServer = this.handleCheckServer.bind(this);
this.state = {
hostname: {
value: "localhost",
isError: false,
errorText: "",
},
serverIp: {
value: "127.0.0.1",
isError: false,
errorText: "",
},
isFormValid: true,
isTestValid: true,
testErrorMessage: "",
isTestWaiting: false,
};
}
componentDidMount() { }
handleCheckServer() {
alert('Alert from Child. Server check will be done here');
}
evaluateFormValid = (prevState) => {
return ((prevState.hostname.value !== "" && !prevState.hostname.isError) &&
(prevState.serverIp.value !== "" && !prevState.serverIp.isError));
};
handleChange = event => {
var valResult;
switch (event.target.id) {
case 'hostname':
valResult = PrimaryFormValidator.validateHostname(event.target.value, event.target.labels[0].textContent);
this.setState({
...this.state,
hostname:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
},
});
break;
case 'serverIp':
valResult = PrimaryFormValidator.validateIpAddress(event.target.value, event.target.labels[0].textContent);
this.setState({
...this.state,
serverIp:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
}
});
break;
default:
}
this.setState(prevState => ({
...prevState,
isFormValid: this.evaluateFormValid(prevState),
}));
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<div className={classes.bigContainer}>
<Paper className={classes.paper}>
<div>
<div>
<Typography variant="subtitle1" gutterBottom className={classes.subtitle1} color='secondary'>
Primary System
</Typography>
<Typography variant="body1" gutterBottom>
Information related with the primary system.
</Typography>
</div>
<div className={classes.bigContainer}>
<form className={classes.formArea}>
<TextField className={classes.formControl}
id="hostname"
label="FQDN Hostname *"
onChange={this.handleChange}
value={this.state.hostname.value}
error={this.state.hostname.isError}
helperText={this.state.hostname.errorText}
variant="outlined" autoComplete="off" />
<TextField className={classes.formControl}
id="serverIp"
label="Server Ip Address *"
onChange={this.handleChange}
value={this.state.serverIp.value}
error={this.state.serverIp.isError}
helperText={this.state.serverIp.errorText}
variant="outlined" autoComplete="off" />
</form>
</div>
</div>
</Paper>
</div>
</React.Fragment>
)
}
}
export default withRouter(withStyles(styles)(PrimaryForm));
(ps: I would like to solve this without another framework like Redux, etc if possible)
Example in Typescript.
The idea is that the parent passes its callback to the child. The child calls the parent's callback supplying its own e.g. child callback as the argument. The parent stores what it got (child callback) in a class member variable and calls it later.
import * as React from 'react'
interface ICallback {
(num: number): string
}
type ChildProps = {
parent_callback: (f: ICallback) => void;
}
class Child extends React.Component {
constructor(props: ChildProps) {
super(props);
props.parent_callback(this.childCallback);
}
childCallback: ICallback = (num: number) => {
if (num == 5) return "hello";
return "bye";
}
render() {
return (
<>
<div>Child</div>
</>
)
}
}
class Parent extends React.Component {
readonly state = { msg: "<not yet set>" };
letChildRegisterItsCallback = (fun: ICallback) => {
this.m_ChildCallback = fun;
}
callChildCallback() {
const str = this.m_ChildCallback? this.m_ChildCallback(5) : "<callback not set>";
console.log("Child callback returned string: " + str);
return str;
}
componentDidMount() {
this.setState((prevState) => { return {...prevState, msg: this.callChildCallback()} });
}
render() {
return (
<>
<Child {...{ parent_callback: this.letChildRegisterItsCallback }} />
<div>{this.state.msg}</div>
</>
)
}
m_ChildCallback: ICallback | undefined = undefined;
}
P.S.
The same code in Javascript. The only difference is that interface, type, readonly and type annotations are taken out. Pasting into here confirms it's a valid ES2015 stage-2 code.
class Child extends React.Component {
constructor(props) {
super(props);
props.parent_callback(this.childCallback);
}
childCallback = (num) => {
if (num == 5) return "hello";
return "bye";
}
render() {
return (
<>
<div>Child</div>
</>
)
}
}
class Parent extends React.Component {
state = { msg: "<not yet set>" };
letChildRegisterItsCallback = (fun) => {
this.m_ChildCallback = fun;
}
callChildCallback() {
const str = this.m_ChildCallback? this.m_ChildCallback(5) : "<callback not set>";
console.log("Child callback returned string: " + str);
return str;
}
componentDidMount() {
this.setState((prevState) => { return {...prevState, msg: this.callChildCallback()} });
}
render() {
return (
<>
<Child {...{ parent_callback: this.letChildRegisterItsCallback }} />
<div>{this.state.msg}</div>
</>
)
}
m_ChildCallback = undefined;
}

Changing className in react based on button click while avoiding more if / elses

Got a small project that I've been working on for past couple weeks. Basic premise is that there is a stepper with steps. User can click on each of them and get a description of what are his to-do's of each step.
There is also a button to complete the step. At the moment I am stuck on the part with making the button work properly.
What I want: When user clicks button to complete step, that stepper item changes its styling (This case classname) to appear as if its complete, and the button get disabled for next step.
I'm now at the point with many if/elses that I no longer have any clue how to finish this task and even if I was to rewrite the if's and else's in a different way I have no clue how as I am pretty new to react.
Some code snippets:
My parent component.
class UserPage extends Component {
state = {
currentStep: 1,
pendingApproval: false
}
clickHandler(e, step) {
e.preventDefault();
this.setState({ currentStep: step })
}
incrimentStep(e, step) {
e.preventDefault();
this.setState({ currentStep: step, pendingApproval: true })
}
render() {
return (
<Grid>
<Grid.Row columns={1}>
<Grid.Column stretched>
<Stepper
clickHandler={this.clickHandler.bind(this)}
steps={this.props.user.process.steps}
pendingApproval={this.state.pendingApproval}
/>
</Grid.Column>
</Grid.Row>
<Grid.Row columns={1}>
<Grid.Column stretched>
<Steps currentStep={this.state.currentStep} steps={this.props.user.process.steps} />
<StepButton
incrimentStep={this.incrimentStep.bind(this)}
currentStep={this.state.currentStep}
steps={this.props.user.process.steps}
pendingApproval={this.state.pendingApproval}
/>
</Grid.Column>
</Grid.Row>
</Grid>
)
}
}
export default UserPage;
My child component that I am trying to fix:
class UserStepper extends Component {
render() {
const steps_length = this.props.steps.length;
let handler = this.props.clickHandler;
// let incompleteStepsArray = []
// let incompleteID = -1;
let pendingApproval = this.props.pendingApproval;
return (
<div id="stepper-container">
{this.props.steps.map(function (step, index) {
if (step.isDone) {
if (index !== steps_length - 1) {
return (
<div key={index} className="completed">
<StepperFill
index={index + 1}
click={handler}
steps={step[index]}
class_name="completecontainer"
/>
<CircleCompleted />
</div>
)
}
else {
return (
<div key={index} className="completed">
<StepperFill
index={index + 1}
click={handler}
steps={step[index]}
class_name="completecontainer"
/>
</div>
)
}
}
else {
{/* incompleteID = incompleteID +1; */}
{/* console.log(incompleteStepsArray) */}
if (index !== steps_length - 1) {
return (
<div key={index} className="incompleted">
<StepperFill
index={index + 1}
click={handler}
steps={step[index]}
class_name="incompletecontainer"
/>
<CircleIncompleted />
</div>
)
}
else {
return (
<div key={index} className="incompleted">
<StepperFill
index={index + 1}
click={handler}
steps={step[index]}
class_name="incompletecontainer"/>
</div>
)
}
}
})}
</div>
)
}
}
//Functional component to decide wether the stepper should be filled or left
blank (Complete or Incomplete)
const StepperFill = (props) => {
return (<div onClick={(e) => props.click(e, props.index)} className=
{props.class_name}>
<p>Step {props.index}</p>
</div>
)
}
const CircleCompleted = () => {
return (
<div className='circle_completed'>
<Icon.Group size='big'>
<Icon size='small' name='checkmark' color='green' />
</Icon.Group>
</div>
)
}
const CircleIncompleted = () => {
return (
<div className='circle_incompleted'>
</div>
)
}
export default UserStepper;
Sorry for the long code, no other idea how to show it otherwise that it would make sense as to what is happening. Any suggestions are appreciated.
Theres many ways you can refactor this but to disable the button a simple approach would be to add a isNextBtnDisabled to your state and pass it down to the button. Whenever you want your button disabled simple set that variable to true.
class UserPage extends Component {
state = {
currentStep: 1,
pendingApproval: false,
isNextBtnDisabled: false,
}
clickHandler(e, step) {
e.preventDefault();
this.setState({ currentStep: step, isNextBtnDisabled: this.state.pendingApproval })
}
incrimentStep(e, step) {
e.preventDefault();
this.setState({ currentStep: step, pendingApproval: true, isNextBtnDisabled: true })
}
render() {
return (
<Grid>
<Grid.Row columns={1}>
<Grid.Column stretched>
<Stepper
clickHandler={this.clickHandler.bind(this)}
steps={this.props.user.process.steps}
pendingApproval={this.state.pendingApproval}
/>
</Grid.Column>
</Grid.Row>
<Grid.Row columns={1}>
<Grid.Column stretched>
<Steps currentStep={this.state.currentStep} steps={this.props.user.process.steps} />
<StepButton
incrimentStep={this.incrimentStep.bind(this)}
currentStep={this.state.currentStep}
steps={this.props.user.process.steps}
pendingApproval={this.state.pendingApproval}
disabled={this.state.isNextBtnDisabled}
/>
</Grid.Column>
</Grid.Row>
</Grid>

Isolating a function when data is mapped in react

I have data being mapped as a repeater. But I need to isolate the opening function (It's an accordion). I'm still learning my way through React. Basically, the accordions load with the state for open: false Once the ListItem is clicked, the HandleClick function toggles the state to open: true. A simple concept, I just need to isolate it so that it works independently. Whereas right now they all open and close at the same time.
Here is the state in a constructor and function
constructor(props) {
super(props);
this.state = {
open: true,
};
}
handleClick = () => { this.setState({ open: !this.state.open }); };
Here is my mapping script in ReactJS
{LicenseItems.map((item, index) => (
<div key={index}>
<ListItem
divider
button
onClick={this.handleClick}>
<ListItemText primary={<CMLabel>{item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open}
timeout="auto"
unmountOnExit>
{item.content}
</Collapse>
</div>
))}
The in dictates whether it is open or not per MaterialUI-Next
Thanks in advance guys!
Not very pretty, but something like this should work:
constructor(props) {
super(props);
this.state = {
open: {},
};
}
handleClick = (idx) => {
this.setState(state => ({open: { [idx]: !state.open[idx]} }))
}
// in render
{LicenseItems.map((item, index) => (
<div key={index}>
<ListItem
divider
button
onClick={() => this.handleClick(index)}>
<ListItemText primary={<CMLabel>{item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open[index]}
timeout="auto"
unmountOnExit>
{item.content}
</Collapse>
</div>
))}
It would be better to create separate Components for that, which have their own open state.
You should create two components for that:
Accordions.js
import React from 'react'
import Accordion from './Accordion'
const Accordions = props => {
return (
props.LicenseItems.map((item, index) => (
<Accordion key={index} item={item} />
))
);
}
export default Accordions;
Accordion.js
import React, { Component } from 'react'
class Accordion extends Component {
constructor(props) {
super(props);
this.state = {
open: true,
};
}
handleClick = () => { this.setState({ open: !this.state.open }); };
render() {
return (
<div>
<ListItem
divider
button
onClick={this.handleClick}>
<ListItemText primary={<CMLabel>{this.props.item.accordion_name}</CMLabel>}/>
</ListItem>
<Collapse
in={!this.state.open}
timeout="auto"
unmountOnExit>
{this.props.item.content}
</Collapse>
</div>
)
}
}
export default Accordion;

Modal not showing proper video in react

Hi I'm implementing a sample app with react,I'm also using youtube api search and react bootstrap.
The idea is the following, I enter a search term, for example "PS4" this will call youtube api search and will bring back 5 matching results in a json format.
With this json, I render a list of thumbnails with videos, title, description,(similar to youtube website). if I click on one of the thumbnails, the idea is to display a modal dialog with the video inside. Here's the problem, it's always loading the same video.
I omit the imports at the beginning of the file
VideoList.js
class VideoList extends React.Component {
constructor(props) {
super(props);
this.openModal = this.openModal.bind(this);
this.close = this.close.bind(this);
this.state = {
showModal: false
}
}
openModal(video) {
this.setState({ showModal: true });
}
close() {
this.setState({ showModal: false });
}
render() {
const videoItems = this.props.videos.map(video =>
<Col xs={6} md={4}>
<Thumbnail onClick={() => this.openModal(video)}
className="thumbnail"
src={video.snippet.thumbnails.default.url}
alt={video.snippet.description}
key={uid()}
>
<h3>{video.title}</h3>
<p>{video.snippet.description}</p>
<hr />
<i>Date: {video.snippet.publishedAt}</i>
<VideoView show={this.state.showModal} video={video} close={this.close} />
</Thumbnail>
</Col>
);
return (
<Grid>
<Row>
{videoItems}
</Row>
</Grid>
);
}
}
export default VideoList;
VideoView.js
const VideoView = props => {
if (!props) {
return <div>{'Could not load the video'}</div>
}
return (
<div className="static-modal">
<Modal show={props.show}>
<Modal.Header>
<Modal.Title>{props.video.snippet.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
One fine body...
</Modal.Body>
<Modal.Footer>
<Button onClick={() => props.close()}>Close</Button>
</Modal.Footer>
</Modal>
</div>
);
}
export default VideoView;
If I click on one of the thumbnails, a modal popup shows with the video (some information of it, not the video itself), the thing is that it always shows the last video (the last in the list of thumbnails)
Another thing: I'm facing a design problem here because I think I should delegate the onclose action to the modal dialog, in this case, the VideoView however the videoView component is a stateless component, I'm only sending some props to render it, (check the onclose callback). Is this a correct approach? Thanks!
You create multiple VideoView elements sharing the same prop this.state.showModal. It means that when this.state.showModal is true then you show all modals at once, and you see only one of them which is on top. Create one VideoView element and pass it a video to show. Also to show/hide modal you can check if this.state.video is not equal to null - if it have value assigned then modal should be visible.
class VideoList extends React.Component {
constructor(props) {
super(props);
this.openModal = this.openModal.bind(this);
this.close = this.close.bind(this);
this.state = {
video: null
}
}
openModal(video) {
this.setState({ video: video });
}
close() {
this.setState({ video: null });
}
render() {
const videoItems = this.props.videos.map(video =>
<Col xs={6} md={4}>
<Thumbnail onClick={() => this.openModal(video)}
className="thumbnail"
src={video.snippet.thumbnails.default.url}
alt={video.snippet.description}
key={uid()}
>
<h3>{video.title}</h3>
<p>{video.snippet.description}</p>
<hr />
<i>Date: {video.snippet.publishedAt}</i>
</Thumbnail>
</Col>
);
return (
<div>
<Grid>
<Row>
{videoItems}
</Row>
</Grid>
<VideoView show={this.state.video !== null} video={this.state.video} close={this.close} />
</div>
);
}
}
export default VideoList;

Categories