I have an app with a list of meal, and clicking on a meal should make a modal appear on the screen with further information about the meal.
So I am trying to code a basic modal as a reusable component using the react-modal package.
However when I try to 'activate' the modal it does not work. the openModal method does get fired but the modal does not show up on the screen.
App.js:
import React from 'react';
import MealCard from './MealCard';
import MealModal from './MealModal';
export default class App extends React.Component {
constructor() {
super();
this.state = {
modalIsOpen: false
}
this.openModal = this.openModal.bind(this);
};
openModal() {
this.setState({modalIsOpen: true});
console.log(this.state.modalIsOpen);
}
render() {
return (
<div>
<div className="app-wrapper" style={{display: 'flex'}}>
<div className="container">
<div className="row">
{[...Array(20)].map((x, i) =>
<div className="col-sm-6 col-xs-12 " key={i} onClick={this.openModal}>
<MealCard />
</div>
)}
</div>
</div>
</div>
<MealModal isOpen={this.state.modalIsOpen}/>
</div>
);
}
}
MealModal.js
import React from 'react';
import Modal from 'react-modal';
const customStyles = {
content : {
top : '50%',
left : '50%',
right : 'auto',
bottom : 'auto',
marginRight : '-50%',
transform : 'translate(-50%, -50%)'
}
};
Modal.setAppElement('#app')
export default class MealModal extends React.Component {
constructor(props) {
super(props);
this.state = {
modalId: 0,
modalIsOpen: false
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
componentWillMount() {
this.setState({modalId: 3})
}
openModal() {
this.setState({modalIsOpen: true});
}
closeModal() {
this.setState({modalIsOpen: false});
}
render() {
return (
<Modal
isOpen={this.props.modalIsOpen}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Meal Modal"
>
<div className="modal-wrapper">
<div className="container text-center">
<h1>Hello</h1>
<h2>ID of this modal is {this.state.modalId}</h2>
<h3>This is an awesome modal.</h3>
<button onClick={this.closeModal}>close</button>
</div>
</div>
</Modal>
)
}
}
You're passing isOpen as props and using modalIsOpen (props) in MealModal component.
As mentioned in the comment, you can just use isOpen={this.props.isOpen}. There's no sense to use two states for serving the same purpose, one is modalIsOpen in App component and other is modalIsOpen in MealModel component
Related
I would like to hover a div, get the image inside that div, show it and then make the image follow my cursor. The hover component is working but then I can't make the follow cursor component work. How would you go about doing this ?
Component number 1 :
import React from 'react';
class FollowMouse extends React.Component {
state = {
xPos: 0,
yPos: 0
};
onMouseMove(e) {
this.setState({
xPos: e.screenX,
yPos: e.screenY
});
}
render() {
return (
<div
onMouseMove={this.onMouseMove.bind(this)}
className="img-ctn"
>
{this.props.children(this.state.xPos, this.state.yPos)}
</div >
);
}
}
export default FollowMouse;
Component 2 :
import React from 'react';
class HoverProject extends React.Component {
state = {
isHovered: false,
};
onMouseEnter() {
this.setState({ isHovered: true });
}
onMouseLeave() {
this.setState({ isHovered: false });
}
render() {
return (
<div
onMouseEnter={this.onMouseEnter.bind(this)}
onMouseLeave={this.onMouseLeave.bind(this)}
className="project-item"
>
{this.props.children(this.state.isHovered)}
</div >
);
}
}
export default HoverProject;
and then the parent component.
import React from 'react';
// modules
import HoverProject from '../modules/HoverProject';
import FollowMouse from '../modules/FollowMouse';
import VLEC from '../images/vlec.png';
class ProjectList extends React.Component {
constructor(props) {
super(props);
this.sels = {
state: 'active'
};
};
render() {
return (
<div className="project-list module">
<div className="sectionTitle">Project I've worked on</div>
{this.props.data.map((res, i) => (
<HoverProject key={i}>
{
isHovered =>
<div className="inner-ctn">
{/* <FollowMouse /> */}
<img className={"project-image " + (isHovered ? this.sels.state : "")} src={VLEC} alt="VLEC" />
<div className="header">
<div className="number">0{res.id + 1}</div>
<div className="name">{res.nomProjet}</div>
</div>
<div className="item-ctn">
<div className="categ">{res.categProjet}</div>
<div className="roles">{res.roles}</div>
<div className="date">{res.date}</div>
</div>
</div>
}
</HoverProject>
))}
</div>
);
}
}
export default ProjectList;
I have no idea what to do with the other component, can you even render childs inside a parent like this ?
I would like pass the props from FollowMouse as style attributes of my img element.
I'm not 100% sure I follow your question, and I don't know what you're expecting this.props.children to do when invoked as a function, but if you want to add props to a child element you can do so via React.cloneElement:
const ParentComponent ({children}) => (
<div>
{React.cloneElement(
React.Children.only(children), // clone the only child...
{ style: { left: xPos, top: yPos} } // ...and add new props
)}
</div>
)
Given:
<ParentComponent>
<div>Wookies and Hats</div>
</ParentComponent>
The child component will get the additional props, the equivalent of:
<ParentComponent>
<div style={{left: xPos, top: yPos}}>Wookies and Hats</div>
</ParentComponent>
I have a Parent component, App.js and a Child component, MealModal.js. When a user click on a specific meal card, it raises a modal that should display further information about the meal.
Hence I try to find a way to dynamically change the modals's data, depending on which meal card is clicked
I have tried to pass the id of the meal to the onClick={this.openModal} function and set the state of modalId is the function. But I got the following error:
Warning: Cannot update during an existing state transition (such as
within render or another component's constructor). Render methods
should be a pure function of props and state; constructor side-effects
are an anti-pattern, but can be moved to 'componentWillMount'.
Here are my components so far:
App.js:
import React from 'react';
import MealCard from './MealCard';
import MealsMap from './MealsMap';
import MealsFilters from './MealsFilters';
import MealModal from './MealModal';
export default class App extends React.Component {
constructor() {
super();
this.state = {
modalIsOpen: false,
modalId: 0
}
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
};
openModal() {
this.setState({modalIsOpen: true});
};
closeModal() {
this.setState({modalIsOpen: false});
};
render() {
return (
<div>
<MealsFilters/>
<div className="app-wrapper" style={{display: 'flex'}}>
<div className="container">
<div className="row">
{[...Array(20)].map((x, i) =>
<div className="col-sm-6 col-xs-12 " key={i} onClick={this.openModal}>
<MealCard />
</div>
)}
</div>
</div>
<MealsMap/>
</div>
<MealModal modalIsOpen={this.state.modalIsOpen} closeModal={this.closeModal} modalId={this.state.modalId}/>
</div>
);
}
}
MealModal.js
import React from 'react';
import Modal from 'react-modal';
const customStyles = {
content : {
}
};
Modal.setAppElement('#app')
export default class MealModal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Modal
isOpen={this.props.modalIsOpen}
onRequestClose={this.props.closeModal}
style={customStyles}
contentLabel="Meal Modal"
>
<div className="modal-wrapper">
<div className="container text-center">
<h1>Hello</h1>
<h2>ID of this modal is {this.props.modalId}</h2>
<h3>This is an awesome modal.</h3>
<button onClick={this.props.closeModal}>close</button>
</div>
</div>
</Modal>
)
}
}
Any idea on how I could do this ?
Ok so I found the solution:
First, I changed onClick={this.openModal} in the parent comoponent to onClick= () => {this.openModal}
Second, I add the id as a parameter:
onClick= () => {this.openModal(i)}
Finally: update the openModal function:
openModal(modalId) {
this.setState({modalIsOpen: true,
modalId});
};
And it works.
openModal(modalId) {
this.setState({
modalId,
modalIsOpen: true
});
};
and modify the call function as
<div className="col-sm-6 col-xs-12" key={i} onClick={() => this.openModal(x) } >
<MealCard/>
</div>
I can not close current modal when open new modal in React js. please help me.
I have parent modal: Register_modal and child of it: RegisterCode_Modal
parent modal is called in header component:
first: Header component
this component call first modal and pass open and close props to it:
import React , {Component} from 'react';
import ReactDOM from 'react-dom';
import {NavLink} from 'react-router-dom';
import Register_Modal from './Register_Modal';
export default class Header extends Component {
constructor() {
super();
this.state = {
modalIsOpen: false
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal(e) {
e.preventDefault();
this.setState({modalIsOpen: true});
}
closeModal(e) {
e.preventDefault();
this.setState({modalIsOpen: false});
}
render() {
return (
<div>
<div className="button navbar-right">
<button className="navbar-btn nav-button wow bounceInRight login" data-wow-delay="0.45s">ورود</button>
<button className="navbar-btn nav-button wow fadeInRight" data-wow-delay="0.48s" onClick={this.openModal} >ثبت نام</button>
<div >
<Register_Modal open={this.state.modalIsOpen} close={this.closeModal} />
</div>
</div>
);
}
}
---------------------------------------------------------------------------
second: parent component
export default class Register_Modal extends Component {
constructor(props){
super(props);
this.state={
codemodal: false
};
this.openCodeModal=this.openCodeModal.bind(this);
this.closeCodeModal=this.closeCodeModal.bind(this);
}
openCodeModal(e){
e.preventDefault();
this.setState({codemodal: true});
}
closeCodeModal(e){
e.preventDefault();
this.setState({codemodal: false});
}
render() {
return (
<div>
<Modal
isOpen={this.props.open}
onRequestClose={this.props.close}
ariaHideApp={false}
contentLabel="selected option"
isClose={this.props.close}
style={customStyles}
>
<h2>salammmmm</h2>
<button onClick={this.props.close} >انصراف</button>
<button onClick={this.openCodeModal} >بعدی</button>
</Modal>
<div className="ReactModalPortal">
<RegisterCode_Modal open={this.state.codemodal} close={this.closeCodeModal} />
</div>
{this.props.close}
</div>
);}
}
------------------------------------------------------------------
third: child component
export default class RegisterCode_Modal extends Component {
constructor(props){
super(props);
console.log("injaaaaa");
}
render() {
return (
<div>
<Modal
isOpen={this.props.open}
onRequestClose={this.props.close}
ariaHideApp={false}
contentLabel="ورود کد"
isClose={this.props.close}
style={customStyles}
>
<h2>مرحله کد</h2>
<button onClick={this.props.close} >تائید</button>
</Modal>
</div>
);}
}
You can simply achieve this by rendering them conditionally.
I personally so this:
export default class RegisterModal extends Component {
state = {
showBaseModal: true,
codemodal: false,
};
openCodeModal = () => {
this.setState({
codemodal: true,
showBaseModal: false,
});
};
closeCodeModal = () => {
this.setState({ codemodal: false });
};
render() {
return (
<div>
{this.state.showBaseModal && (
<Modal
isOpen
onRequestClose={this.props.close}
ariaHideApp={false}
isClose={this.props.close}
>
<button onClick={this.props.close}>Close</button>
<button onClick={this.openCodeModal}>Next</button>
</Modal>
)}
{this.state.codemodal && (
<RegisterCode_Modal
open={this.state.codemodal}
close={this.closeCodeModal}
/>
)}
</div>
);
}
}
Adding an extra state for base modal. On openCodeModal event, toggle it to false to stop both modals.
Set isOpen always to true for both modals, and then render RegisterModal component conditionally.
I'm new to React so bear with me.
I'm trying to create a modal component that will be triggered from a onClick() function from any global element i.e: link, button, span or whatever throughout the whole app.
import React from 'react';
import ReactDOM from 'react-dom';
const display = {
display: 'block'
};
const hide = {
display: 'none'
};
class Modal extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
toggle: false
}
}
toggle(event) {
this.setState(prevState => ({
toggle: !prevState.toggle
}));
}
render() {
return (
<div>
<button onClick={this.toggle}>Show Modal</button>
<div className="modal" style={this.state.toggle ? display : hide} >
<div className="modal-content">
{this.props.children}
<button onClick={this.toggle}>Close</button>
</div>
</div>
</div>
);
}
}
module.exports = Modal;
You can use react-bootstrap-modal:
npm install --save react-bootstrap-modal
Then in your component:
import React from 'react';
import Modal from 'react-bootstrap-modal';
export default class ModalExample extends React.Component {
constructor(props){
super(props);
this.state = {
open: false,
}
}
openModal = () => this.setState({ open: true })
closeModal = () => this.setState({ open: false })
render(){
return (
<div>
<button type='button' onClick={this.openModal}>Launch modal</button>
<Modal
show={this.state.open}
onHide={this.closeModal}
aria-labelledby="ModalHeader"
>
<Modal.Header>
<Modal.Title id='ModalHeader'>A Title Goes here</Modal.Title>
<div onClick={this.closeModal}>CLOSE HERE</div>
</Modal.Header>
<Modal.Body>
<p>Some Content here</p>
</Modal.Body>
<Modal.Footer>
// If you don't have anything fancy to do you can use
// the convenient `Dismiss` component, it will
// trigger `onHide` when clicked
<Modal.Dismiss className='btn btn-default'>Cancel</Modal.Dismiss>
// Or you can create your own dismiss buttons
<button className='btn btn-primary' onClick={this.closeModal}>
CLOSE HERE TOO
</button>
</Modal.Footer>
</Modal>
</div>
)
}
}
For further reference, please go here:
https://github.com/jquense/react-bootstrap-modal
You may also need to include bootstrap-CSS file if necessary! Please post here some errors if any, thanks
I have just started using React and working on a small app, in the meantime I made a small show and hide modal. I wanted to know the way I have made it is a wrong way to do it. If this is an anti-pattern how should I go about it?
class App extends Component {
constructor(props) {
super(props);
this.state = {show: false};
this.showModal = this.showModal.bind(this);
}
render() {
return (
<div>
<h2 className={styles.main__title}>Helloooo!</h2>
<Modal ref='show'/>
<button onClick={this.showModal} className={styles.addtask}>➕</button>
</div>
);
}
showModal(){
this.setState({
show: true
});
this.refs.show.showModal();
}
}
The modal component which i have made is using this logic, it hooks the dom elements and modifies using the document.queryselector. Is this a right way to do the dom manipulation in react.
The modal code which i have used is this :
class Modal extends Component {
constructor() {
super();
this.hideModal = this.hideModal.bind(this);
this.showModal = this.showModal.bind(this);
this.state = { modalHook: '.'+styles.container };
}
render() {
return (
<div>
<div onClick={this.hideModal} className={styles.container}>
<div className={styles.container__content}>
<div className={styles.card}>
<div className={styles.card__header}>
<h2>Add new task</h2>
</div>
<div className={styles.card__main}>
<Input type="text" placeholder="enter the task title" />
<Input type="textarea" placeholder="enter the task details" />
</div>
<div className={styles.card__actions}>
</div>
</div>
</div>
</div>
</div>
);
}
showModal(){
let container = document.querySelector(this.state.modalHook);
container.classList.add(styles.show);
}
hideModal(e){
let container = document.querySelector(this.state.modalHook);
if(e.target.classList.contains(styles.container)){
container.classList.remove(styles.show);
}
}
}
Your example looks good and simple, but accordingly to this it is better don't overuse refs.
And also it might be helpful to lifting state up, like described here.
Here my example:
class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {show: props.show};
}
componentDidUpdate(prevProps, prevState) {
let modal = document.getElementById('modal');
if (prevProps.show) {
modal.classList.remove('hidden');
} else {
modal.className += ' hidden';
}
}
render() {
return (
<div id="modal" className={this.state.show ? '' : 'hidden'}>
My modal content.
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
show: !prevState.show
}));
}
render() {
return (
<div>
<button onClick={this.handleClick}>
Launch modal
</button>
<Modal show={this.state.show} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Here i don't pretend for ultimate truth, but try to provide another option how you can reach desired result.
To do what you require you don't need to use refs at all. You can pass the state down the to child component as a prop. When the state updates the prop will automatically update. You can then use this prop to switch a class. You can see it in action on jsbin here
const Modal = (props) => {
return (
<div className={props.show ? 'show' : 'hide'}>modal</div>
)
}
const styles = {
main__title: 'main__title',
addtask: 'addtask'
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
this.toggleModal = this.toggleModal.bind(this);
}
render() {
return (
<div>
<h2 className={styles.main__title}>Helloooo!</h2>
<Modal show={this.state.show} />
<button onClick={this.toggleModal} className={styles.addtask}>➕</button>
</div>
);
}
toggleModal(){
this.setState({
show: !this.state.show
});
}
}
ReactDOM.render(<App />, document.getElementById('root'));