React setState with media queries - reactjs

Is there any way to setState({collapse: true}) for mobile screens only? How can i toggle the this.state.collapse based on current window size?
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import $ from 'jquery';
import { Container, Row, Col, Collapse, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink } from 'reactstrap';
import { css } from 'glamor';
import { ToastContainer } from 'react-toastify';
import toast from '../toast';
import { BarLoader } from 'react-spinners';
// ---------------- Custom components
import DashboardNavbar from '../DashboardPage/Dashboard/DashboardNavbar/DashboardNavbar';
import Footer from '../Footer/Footer';
import './VideoPage.css';
class VideoPage extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
collapsed: false
};
this.toggleLoader = this.toggleLoader.bind(this);
this.notifySuccess = this.notifySuccess.bind(this);
this.notifyError = this.notifyError.bind(this);
this.toggleNavbar = this.toggleNavbar.bind(this);
}
notifySuccess(msg) {
toast.success(msg);
}
notifyError(msg) {
toast.error(msg);
}
toggleLoader() {
this.setState({
loading: !this.state.loading
});
}
// isAuthenticated() {
// const token = localStorage.getItem('authToken');
// if (token) {
// return true;
// }
// }
toggleNavbar() {
this.setState({
collapsed: !this.state.collapsed
});
}
render() {
const currentLocationPath = this.props.location.pathname;
const videoPage = currentLocationPath.includes('/video');
return (
<div className="VideoPage d-flex flex-column flex-grow">
<div className="VideoPageMain d-flex flex-grow">
<Container fluid>
<Row>
<DashboardNavbar videoPage={videoPage} />
</Row>
<Row>
<Col xs="12" sm="3">
<div className="sidebarMenu">
<Navbar dark>
<NavbarBrand className="mr-auto">Menu</NavbarBrand>
<NavbarToggler onClick={this.toggleNavbar} className="mr-2 d-sm-none" />
<Collapse isOpen={!this.state.collapsed} navbar>
<Nav navbar>
<NavItem>
<NavLink href="/components/">Components</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/reactstrap/reactstrap">Github</NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>
</div>
</Col>
<Col xs="12" sm="9">.col</Col>
</Row>
</Container>
</div>
<Footer />
</div>
)
}
}
export default VideoPage;
basically i want the list to be hidden on mobile as there is button to toggle it which is hidden from tablet size and onwards.

It looks like there's a library for that: https://github.com/contra/react-responsive
Otherwise, you could add a listener to the resize event of window and fire that listener in the constructor to check the size.

You have 2 options:
1st option
Toggle classNames and let your CSS handles showing/hiding on different viewports
2nd option
use window.innerWidth in your isCollapsed
<Collapse isOpen={!this.state.collapsed && window.innerWidth < 768} navbar>
768 is just as an example

Related

How to close sidebar when clicking link?

I am trying to get my sidebar to close when I click on any of the menu options. I was able to get the sidebar to close/open whenever I click on the burger icon, but not sure if I am supposed to make my sidebar component a class and have its own state. Below are my navigation and sidebar components.
import React from 'react';
import { Link } from 'react-router-dom';
import { ReactComponent as MenuIcon } from '../../assets/menu.svg';
import { ReactComponent as CloseIcon } from '../../assets/x-mark.svg';
import './navigation.styles.scss';
import Sidebar from '../sidebar/sidebar.component';
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isSidebarHidden: true
};
this.handleSidebar = this.handleSidebar.bind(this);
}
handleSidebar() {
this.setState({ isSidebarHidden: !this.state.isSidebarHidden });
}
render() {
const { isSidebarHidden } = this.state;
return (
<div className='navigation'>
<div className='logo-container'>
<Link className='logo' to='/'>
NAME
</Link>
</div>
<div className='navigation-options'>
<Link className='option' to='/projects'>
PROJECTS
</Link>
<Link className='option' to='contact'>
CONTACT
</Link>
{isSidebarHidden ? (
<MenuIcon className='menu-icon' onClick={this.handleSidebar} />
) : (
<CloseIcon className='menu-icon' onClick={this.handleSidebar} />
)}
</div>
{isSidebarHidden ? null : <Sidebar />}
</div>
);
}
}
export default Navigation;
import React from 'react';
import { Link } from 'react-router-dom';
import './sidebar.styles.scss';
const Sidebar = () => (
<div className='sidebar'>
<Link className='sidebar-option' to='/projects'>
PROJECS
</Link>
<Link className='sidebar-option' to='/contact'>
CONTACT
</Link>
</div>
);
export default Sidebar;
You could create a method to hide the sidebar and pass it to the Sidebar component, so it executes when you click the links.
const Sidebar = ({hideSidebar}) => (
<div className='sidebar'>
<Link onClick={hideSidebar} className='sidebar-option' to='/projects'>
PROJECS
</Link>
<Link onClick={hideSidebar} className='sidebar-option' to='/contact'>
CONTACT
</Link>
</div>
);
Or you could also execute it every time you move to a different path listening to the browser history with react-router.
import { browserHistory } from 'react-router';
browserHistory.listen(handleRouteChange);
I suggest controlling the component with props instead of using if statement inside the parent component.
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import './sidebar.styles.scss';
const Sidebar = ({ visibility, setVisibility }) => {
if (visibility) {
return (
<div className='sidebar'>
<Link className='sidebar-option' to='/projects' onClick={() => setVisibility()}>
PROJECS
</Link>
<Link className='sidebar-option' to='/contact' onClick={() => setVisibility()}>
CONTACT
</Link>
</div>
)
}
return null
};
export default Sidebar;
As you see, I passed setVisibility prop to onClick callback on the sidebar links and checked if visibility is true then return the sidebar contents. So in this step, we just need to pass this.handleSidebar to setVisibility prop and the parent state isSidebarHidden to the visibility prop.
import React from 'react';
import { Link } from 'react-router-dom';
import { ReactComponent as MenuIcon } from '../../assets/menu.svg';
import { ReactComponent as CloseIcon } from '../../assets/x-mark.svg';
import './navigation.styles.scss';
import Sidebar from '../sidebar/sidebar.component';
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = { isSidebarHidden: true };
this.handleSidebar = this.handleSidebar.bind(this);
}
handleSidebar() {
this.setState({ isSidebarHidden: !this.state.isSidebarHidden });
}
render() {
const { isSidebarHidden } = this.state;
return (
<div className='navigation'>
<div className='logo-container'>
<Link className='logo' to='/'>
NAME
</Link>
</div>
<div className='navigation-options'>
<Link className='option' to='/projects'>
PROJECTS
</Link>
<Link className='option' to='contact'>
CONTACT
</Link>
{isSidebarHidden ? (
<MenuIcon className='menu-icon' onClick={this.handleSidebar} />
) : (
<CloseIcon className='menu-icon' onClick={this.handleSidebar} />
)}
</div>
<Sidebar visibility={isSidebarHidden} setVisibility={this.handleSidebar} />
</div>
);
}
}
export default Navigation;
Then it works.
For the people using bootstrap offcanvas as a sidebar there is a very easy way to do it using only bootstrap and with no JavaScript.
<li data-bs-dismiss="offcanvas">Skills</li>
The above code represent li as one of the item in the sidebar and on upon clicking it takes you to skill section and also closes as it is in dismiss state.

No text shown in dialog box (react js dialog box)?

I use https://www.npmjs.com/package/react-bootstrap-dialog#dialogprompt-generators for my notification generating module. but only display buttons and no any text message shown in dialogbox..
enter image description here
onClick () {
this.dialog.show({
title: 'Greedings',
body: 'How are you?',
actions: [
Dialog.CancelAction(),
Dialog.OKAction()
],
bsSize: 'small',
onHide: (dialog) => {
dialog.hide()
console.log('closed by clicking background.')
}
})
}
This is the code part i used for that..Help me..
I have used material dashboard react free template for my project development, So in this dialog box doesn't work, but when i use codesandbox, it works properly, doesn't it work with material dashboard? .I can't understand why,If you know, Help me..
codesandbox.io/s/amazing-glade-lh5tl
import React from "react";
import firebase from "../../config/firebase.js";
import PropTypes from "prop-types";
import carfix from "./s.jpg";
// react plugin for creating charts
import {Link, withRouter} from 'react-router-dom';
import ChartistGraph from "react-chartist"; // #material-ui/core
import withStyles from "#material-ui/core/styles/withStyles";
import Icon from "#material-ui/core/Icon"; // #material-ui/icons
import Store from "#material-ui/icons/Store";
import Warning from "#material-ui/icons/Warning";
import DateRange from "#material-ui/icons/DateRange";
import LocalOffer from "#material-ui/icons/LocalOffer";
import Update from "#material-ui/icons/Update";
import ArrowUpward from "#material-ui/icons/ArrowUpward";
import AccessTime from "#material-ui/icons/AccessTime";
import Accessibility from "#material-ui/icons/Accessibility";
import BugReport from "#material-ui/icons/BugReport";
import Code from "#material-ui/icons/Code";
import Cloud from "#material-ui/icons/Cloud"; // core components
import GridItem from "components/Grid/GridItem.jsx";
import GridContainer from "components/Grid/GridContainer.jsx";
import Table from "components/Table/Table.jsx";
import Tasks from "components/Tasks/Tasks.jsx";
import CustomTabs from "components/CustomTabs/CustomTabs.jsx";
import Danger from "components/Typography/Danger.jsx";
import Card from "components/Card/Card.jsx";
import CardHeader from "components/Card/CardHeader.jsx";
import CardIcon from "components/Card/CardIcon.jsx";
import CardBody from "components/Card/CardBody.jsx";
import CardFooter from "components/Card/CardFooter.jsx";
import WorkAssign from "pages/work_assignmt.js";
import WorkDone from "pages/work_done.js";
import Modal from 'react-bootstrap/Modal';
import {Button} from 'react-bootstrap'
import Dialog from 'react-bootstrap-dialog'
import { bugs, website, server } from "variables/general.jsx";
import { dailySalesChart, emailsSubscriptionChart, completedTasksChart } from "variables/charts.jsx";
import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardStyle.jsx";
class Dashboard extends React.Component { constructor(props) {
super(props);
this.onClick = this.onClick.bind(this)
this.state = {
field1:0,
field2:0,
field3:0,
isDialogOpen: false
}; }
onClick () {
this.dialog.show({
title: 'Greedings',
body: 'How are you?',
actions: [
Dialog.CancelAction(),
Dialog.OKAction()
],
bsSize: 'small',
onHide: (dialog) => {
dialog.hide()
console.log('closed by clicking background.')
}
}) }
componentWillMount = async() =>{
this.setFieldData(); };
handleChange = (event, value) => {
this.setState({ value }); };
handleChangeIndex = index => {
this.setState({ value: index }); };
setFieldData = async() => {
var ref = firebase.database().ref("Daily Work Data").child("02-10-2019").child("Field 1");
var sum=0;
var ref = firebase.database().ref("Daily Work Data").child("02-10-2019").child("Field 2");
sum=0;
this.setState({field2: sum});
var ref = firebase.database().ref("Daily Work Data").child("02-10-2019").child("Field 3");
sum=0;
await ref.once('value',function (snapshot) {
snapshot.forEach(element => {
sum = sum + element.val().amount;
});
});
this.setState({field3: sum});
};
render() { const { classes } = this.props;
return (
<div
className="App"
style={{
backgroundImage: `linear-gradient(0deg,rgba(20,100,20,0.5), rgba(9, 93, 225, 0.0)),url(${carfix})`
}}>
<div className="wrappe">
<div>
<Dialog ref={(component) => { this.dialog = component }} />
</div>
<div>
<GridContainer>
<GridItem xs={12} sm={6} md={4}>
<Card>
<Button variant="underlined"
onClick={this.onClick}>
<CardHeader color="warning" stats icon>
<CardIcon color="warning">
<i class="material-icons">notifications_active</i>
</CardIcon>
<p className={classes.cardCategory}></p>
<h4 className={classes.cardTitle}>New Notifications</h4>
</CardHeader>
<CardFooter stats>
<div className={classes.stats}>
<hr/>
</div>
</CardFooter>
</Button>
</Card>
</GridItem>
<GridItem xs={12} sm={6} md={4}>
<Card>
<Button variant="underlined"
onClick={this.onClick}>
<CardHeader color="primary" stats icon>
<CardIcon color="primary">
<i class="material-icons">pan_tool</i>
</CardIcon>
<p className={classes.cardCategory}></p>
<h4 className={classes.cardTitle}>Pending Notifications</h4>
</CardHeader>
<CardFooter stats>
<div className={classes.stats}>
<hr/>
</div>
</CardFooter>
</Button>
</Card>
</GridItem>
<GridItem xs={12} sm={6} md={4}>
<Card>
<Button variant="underlined"
onClick={this.onClick}>
<CardHeader color="danger" stats icon>
<CardIcon color="danger">
<i class="material-icons">thumb_up</i>
</CardIcon>
<p className={classes.cardCategory}></p>
<h4 className={classes.cardTitle}>Responded Notifications</h4>
</CardHeader>
<CardFooter stats>
<div className={classes.stats}>
<hr/>
</div>
</CardFooter>
</Button>
</Card>
</GridItem>
</GridContainer>
<div>
</div>
</div> </div> </div>
); } }
Dashboard.propTypes = { classes: PropTypes.object.isRequired };
export default withStyles(dashboardStyle)(Dashboard);

i need to chnge the button from login to add to cart when user login immediately

how can i change the state of login to add to cart when the user login in first the header nav item will be login if the user login then i want the button to change to add to cart in React
i have used session.getitem() to check the whether their is data or not in component did mount and in component did update i have updated the state but some how the component did mount will not call
import React from 'react';
import { FormGroup, ControlLabel, FormControl } from 'react-bootstrap';
import { UserData } from '../../PostData';
import { ClipLoader } from 'react-spinners';
import { Redirect } from 'react-router-dom'
class Login extends React.Component {
state = {
username: undefined,
email: undefined,
loading: false,
redirect: false
}
onSubmit = (e) => {
e.preventDefault();
this.setState({ loading: true });
if (this.state.email && this.state.email !== '') {
try {
UserData(this.state.username, this.state.email).then(result => {
this.setState({ loading: false })
if (result.length) {
sessionStorage.setItem("login", JSON.stringify(result));
this.setState({ redirect: true })
} else {
alert("please enter the write email and username");
}
})
}
catch (e) {
console.log(e)
}
} else {
console.log("black")
}
}
onChangeHandle = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
render() {
if (this.state.redirect) {
return <Redirect to="/" />
}
return (
<div>
<div style={{ position: 'absolute', top: '20%', left: '50%', zIndex: '111111' }}>
<ClipLoader
sizeUnit={"px"}
size={150}
color={'#123abc'}
loading={this.state.loading}
/>
</div>
<div className="container">
<form onSubmit={this.onSubmit}>
<FormGroup
controlId="formBasicText"
// validationState={this.getValidationState()}
>
<ControlLabel>username</ControlLabel>
<FormControl
type="text"
placeholder="Enter username"
name="username"
onChange={this.onChangeHandle}
/>
<FormControl.Feedback />
<ControlLabel>Email</ControlLabel>
<FormControl
type="text"
name="email"
placeholder="Enter email"
onChange={this.onChangeHandle}
/>
<FormControl.Feedback />
<input type="submit" className="btn btn-primary" value="login"></input>
</FormGroup>
</form>
</div>
</div>
)
}
}
export default Login;
and in header
import React from 'react';
import { NavLink } from 'react-router-dom';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
class Header extends React.Component {
state = {
login: false
}
componentDidMount() {
const data = sessionStorage.getItem("login");
if (data) {
this.setState({ login: !this.state.login })
}
}
componentDidUpdate(prevProps, prevState) {
if (prevState.login !== this.state.login) {
this.setState({ login: true })
}
}
render() {
return (
<Navbar inverse collapseOnSelect>
<Navbar.Header>
<Navbar.Brand>
<NavLink to="/" >Home</NavLink>
</Navbar.Brand>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav>
<LinkContainer to="/shop">
<NavItem eventKey={1}>Shop</NavItem>
</LinkContainer>
</Nav>
<Nav pullRight>
{this.state.login ?
<LinkContainer to="/addtocart">
<NavItem eventKey={1}>Add To cart</NavItem>
</LinkContainer>
:
<LinkContainer to="/login">
<NavItem eventKey={1}>Login</NavItem>
</LinkContainer>
}
<LinkContainer to="/signip">
<NavItem eventKey={1}>Sigup</NavItem>
</LinkContainer>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
}
export default Header;

React - fixed navbar and nav-tab

I am using reactstrap package in for my project. So, I have created a HeaderComponent which is a Navbar which is fixed at top fixed=top.
import React from 'react';
import Context from '../provider'
import {
Collapse,
Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink,
Form, FormGroup, Label, Input, Button,
} from 'reactstrap';
import LoginComponent from './LoginComponent'
import SignupComponent from './SignupComponent'
class HeaderComponent extends React.Component {
render() {
return (
<Context.Consumer>
{context => {
return (
<Navbar color="light" light expand="md" fixed="top">
<NavbarBrand href="/">Reddit</NavbarBrand>
<NavbarToggler onClick={() => context.toggleNavbar()} />
<Collapse isOpen={context.navbarOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem><LoginComponent /></NavItem>
<NavItem><SignupComponent /></NavItem>
</Nav>
</Collapse>
</Navbar>
)
}}
</Context.Consumer>
)
}
}
export default HeaderComponent;
I also have a TabComponent:
import React, {Component} from 'react'
import Context from '../../provider'
import {Nav, NavItem, NavLink} from 'reactstrap'
import classnames from 'classnames'
class TabComponent extends Component {
render() {
return (
<Context.Consumer>
{context => (
<Nav tabs>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '1' })}
onClick={() => { context.toggleTab('1'); }}
>
Home
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '2' })}
onClick={() => { context.toggleTab('2'); }}
>
Popular
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '3' })}
onClick={() => { context.toggleTab('3'); }}
>
All
</NavLink>
</NavItem>
</Nav>
)}
</Context.Consumer>
)
}
}
export default TabComponent;
I am making the HeaderComponent fixed but I don't know how to make the TabComponent fixed below the HeaderComponent.
Based on this answer, I did the following:
TopComponent
import React, {Component} from 'react'
import HeaderComponent from './HeaderComponent'
import TabComponent from './TabComponent'
import {Row, Col, Container} from 'reactstrap'
import './style.css'
export default class TopComponent extends Component {
render() {
return (
<div className='vert-align'>
<Container>
<Row><Col><HeaderComponent /></Col></Row>
<Row><Col><TabComponent /></Col></Row>
</Container>
</div>
)
}
}
style.css
.vert-align {
top:0;
position: fixed;
z-index:100;
}
They are now fixed to the top one below the other but, they are not covering the complete width of screen now!
The easiest in my opinion would be to make a parent component FixedTopComponent for both HeaderComponent and TabComponent, and fix this one to the top fixed=top. then you just have to align the two children components vertically, using either bootstrap rows or {display: flex; flex-direction: column} in your css.
Here's an example:
class FixedTopComponent extends React.Component {
render() {
const vert_align = {
display: 'flex',
flexDirection: 'column'
}
<div id='fixed-top" style={vert_align} fixed='top'>
<HeaderComponent />
<TabComponent />
</div>
}
}
Edit: For your second issue (not sure cause I never used reactstrap), try:
import React, {Component} from 'react'
import HeaderComponent from './HeaderComponent'
import TabComponent from './TabComponent'
import {Row, Col, Container} from 'reactstrap'
import './style.css'
export default class TopComponent extends Component {
render() {
return (
<Container fluid className='vert-align'>
<Row><Col><HeaderComponent /></Col></Row>
<Row><Col><TabComponent /></Col></Row>
</Container>
)
}
}

react-konva How to change image after uploading?

I'm working on a small project that allows user to upload image and then the image will be displayed on a canvas.
I'm using react-konva for this.
I have a container component called DesignPage, which manages the state and pass event handlers to its children.
Inside this DesignPage component, I have 2 other components: Tools - Canvas
When I upload an image using Tools component, the image should be displayed on Canvas component.
I'm using react-dropzone inside Tools component to handle file upload
Inside this Canvas component, there is a child component called DesignImage, which is just for displaying the image.
But the thing is, it just doesn't change the image on canvas when I upload.
How can I fix that?
Here is my code:
DesignPage component:
import React, {Component} from 'react';
import {
Row,
Col
} from 'reactstrap';
import Tools from "../components/DesignPage/Tools";
import Canvas from "../components/DesignPage/Canvas";
import Styles from "../components/DesignPage/Styles";
class DesignPage extends Component {
state = {
text: '',
image: '',
files: []
};
static propTypes = {};
handleTextChange = e => {
this.setState({text: e.target.value});
};
handleFileDrop = files => {
this.setState({
files,
image: files[0].preview
});
};
render() {
return <Row>
<Col xs={12} md={4}>
<Tools
files={this.state.files}
onTextChange={this.handleTextChange}
onFileDrop={this.handleFileDrop}/>
</Col>
<Col xs={12} md={5}>
<Canvas
text={this.state.text}
image={this.state.image}/>
</Col>
<Col xs={12} md={3}>
<Styles/>
</Col>
</Row>;
}
}
export default DesignPage;
Tools component:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
TabContent,
TabPane,
Nav,
NavItem,
NavLink,
Row,
Col,
FormGroup,
Label
} from 'reactstrap';
import classnames from 'classnames';
import Dropzone from 'react-dropzone';
class Tools extends Component {
state = {
activeTab: '1'
};
toggle = (tab) => {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
};
render() {
return <Row>
<Col xs={12}>
<div>
<Nav tabs justified>
<NavItem>
<NavLink
className={classnames({active: this.state.activeTab === '1'})}
onClick={() => {
this.toggle('1');
}}
>
Text
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({active: this.state.activeTab === '2'})}
onClick={() => {
this.toggle('2');
}}
>
Art
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={this.state.activeTab}>
<TabPane tabId="1">
<Row>
<Col sm="12">
<FormGroup>
<Label for={"custom-text"}>Enter text below</Label>
<textarea
className={"form-control"}
id={"custom-text"}
onChange={this.props.onTextChange}/>
</FormGroup>
<FormGroup>
<Label for={"font-select"}>Choose a font</Label>
</FormGroup>
</Col>
</Row>
</TabPane>
<TabPane tabId="2">
<Row>
<Col sm="12">
<FormGroup>
<div className="dropzone-container">
<Dropzone onDrop={this.props.onFileDrop}>
<p>Drop a design here, or click to select design to upload.</p>
</Dropzone>
</div>
</FormGroup>
</Col>
</Row>
</TabPane>
</TabContent>
</div>
</Col>
</Row>;
}
}
Tools.propTypes = {
files: PropTypes.array.isRequired,
onTextChange: PropTypes.func.isRequired,
onFileDrop: PropTypes.func.isRequired
};
export default Tools;
Canvas component:
import React from 'react';
import PropTypes from 'prop-types';
import {
Row,
Col
} from 'reactstrap';
import {Stage, Layer} from 'react-konva';
import UserText from "./Canvas/UserText";
import DesignImage from "./Canvas/DesignImage";
const Canvas = props => {
return <Row>
<Col xs={12} className={"canvas-container"}>
<div className={"object-container"}>
<img className={"object-img"} src={"images/iPhone5A.png"} alt={"iPhone5A"}/>
<div className="drawing-area">
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<UserText text={props.text}/>
<DesignImage image={props.image}/>
</Layer>
</Stage>
</div>
</div>
</Col>
</Row>;
};
Canvas.propTypes = {
text: PropTypes.string.isRequired,
image: PropTypes.string.isRequired
};
export default Canvas;
DesignImage component:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Image} from 'react-konva';
class DesignImage extends Component {
state = {
image: null
};
static propTypes = {
image: PropTypes.string.isRequired
};
componentDidMount() {
const image = new window.Image();
image.src = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRYTULZCGUVEQJEXt9iB8PU4Kb2FMS9Z6ufR1FnQTdrEl5uBOl52Q';
image.onload = () => {
// setState will redraw layer
// because "image" property is changed
this.setState({
image: image
});
};
}
render() {
return <Image image={this.props.image} draggable={true}/>;
}
}
export default DesignImage;
You need write a code to update the image when the component has a new image from props.
class DesignImage extends Component {
state = {
image: null
};
static propTypes = {
image: PropTypes.string.isRequired
};
componentDidMount() {
this.updateImage();
}
componentDidUpdate() {
this.updateImage();
}
updateImage() {
const image = new window.Image();
image.src = this.props.image;
image.onload = () => {
this.setState({
image: image
});
};
}
render() {
return <Image image={this.state.image} draggable={true}/>;
}
}
Update:
You can use use-image hook for simpler image loading:
import useImage from 'use-image';
const DesignImage = ({ image }) => {
const imgElement = useImage(image);
return <Image image={imgElement} draggable={true}/>;
}

Resources