I have this Footer child, which has the Modal parent's cancel function passed to it in the props, but it won't execute the parent's "handleCancel" function.
const PageFooter = (props) => {
const { handleCancel} = props;
const modalStyleClass = useModalStyles();
return(
<footer className={modalStyleClass.modalFooter}>
<div className="container-fluid">
<div className="row">
<div className="col-sm-6">
</div>
<div className="col-sm-6 text-right">
<button className={modalStyleClass.cancelButton}
onClick={handleCancel}>
</button>
</div>
</div>
</div>
</footer>
)}
export default PageFooter;
The generic edit modal parent get's it's props from whatever other parent component called it: That parent implements the state of the modal
with
const [isModalShown, toggleModal] = React.useState(false);
The generic 'EditModal' as parent to the child footer component's code:
export function GenericEditModal (props) {
const {isModalShown, title, closeModal, } = props;
const HandleCancel = () => {
closeModal();
};
return (
<form >
<div>
<Modal
className={modalStyleClass.modal}
open={isModalShown}
closeModal={handleCloseModal}
onClose={handleCloseModal}
>
<div className={modalStyleClass.paper} style={{ top: '0px',padding:'0px', }} >
<ModalHeader>
handleCancel={HandleCancel}
</ModalHeader>
{ markup }
</div>
<Footer>
handleCancel={HandleCancel}
</Footer>
</div>
</Modal>
</div>
</form>
);
};
export const GenericEditModal = React.memo(GenericEditModal);
Pass to child like this:
<Footer handleCancel={HandleCancel}/>
Related
on my Project I have a banner on top of my site with 2 buttons. when I click the button profile I want it to change the css style of a div in another component.
this is my code for the banner:
import Profile from "./Profile";
function Banner() {
const invis=false;
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={Profile.changeStyle}>Profile</button>
</span>
</div>
);
}
export default Banner;
this is my code for the div in the other component:
import "../index.css";
import React, { useState } from "react";
const Profile = () => {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div>
<div className={style}> hellllo</div>
</div>
);
};
export default Profile;
I can only find information about this with parent-child components.
They said I should use a usestate import but I can't seem to get it working. what's the proper way to do this?
All you need is lift your state to parent component, if you have a long trip to your common ancestor you can try to use a context. Attached a working example. Hope it helps!
const Banner = ({ onClickHandler }) => {
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={() => onClickHandler()}>Profile</button>
</span>
</div>
)}
const Profile = ({ style }) => {
return (
<div>
<div className={style}>I'm your profile :)</div>
</div>
);
};
const App = () => {
// We lift the state
const [style, setStyle] = React.useState("profile-hidden");
const profileHandler = () => {
setStyle(style === 'profile-hidden'
? 'profile-displayed'
: 'profile-hidden')
}
return(
<div>
<Banner onClickHandler={profileHandler} />
<Profile style={style} />
</div>
)
}
// Render
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
.profile-hidden {
display: none;
}
.profile-displayed {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>
You cannot use this syntax for React Components COMPONENT.method
, in your case onClick={Profile.changeStyle} !
Instead you should make Banner parent component and use Profile component as child inside it or vise versa !
then You should pass the state style as props so then you will be able to use its value.
your code should look like this :
function Banner() {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={changeStyle}>Profile</button>
</span>
<Profile style={style} />
</div>
);
}
export default Banner;
and your Profile component :
const Profile = (props) => {
return (
<div>
<div className={props.style}> hellllo</div>
</div>
)
}
I am new to reacting and having trouble understanding how to pass data meta into each modal when an image is clicked and update the modal with the clicked data info. Following in my bare minimum code for sake of example
app.js
<div className="movie">
<Modal >hello world/*making sure the static text is passed into as children prop*/</Modal>
{movies.length > 0 &&
movies.map((data) => {
return <Library key={data.id} {...data} searchTerm={searchTerm} />;
})}
</div>
modal.jsx
export default function Index({children}) {
const [isOpen, setIsOpen] = useState(true)
return (
isOpen && (
<div className='modalContainer'>
<div className="modal">
<div className="close">
<button onClick={()=>{
setIsOpen(false)
}}>close</button>
</div>
{children}
</div>
</div>
)
)
}
Library.jsx
import "./Library.scss";
import {Link} from "react-router-dom";
const IMG_API = "http://image.tmdb.org/t/p/w1280";
const Library = ({
title,
poster_path,
release_date,
}) => {
return (
<div>
<Link to="/modal">
<img src={IMG_API + poster_path} alt={title} />
</Link>
<div className="meta">
<h5>{title}</h5>
<p>{release_date.slice(0, 4)}</p>
</div>
</div>
);
};
export default Library;
You should declare the isOpen state in the upper-level component so you can actually open the modal on some kind of event.
Also, you should declare a props where to pass the actual text to the Modal component:
const [isOpen, setIsOpen] = useState(false)
const handleOpen = () => setIsOpen(true);
<div className='movie'>
<Modal isOpen={isOpen} setIsOpen={setIsOpen} text='Hello, world' />
{movies.length > 0 &&
movies.map((data) => {
return <Library key={data.id} {...data} searchTerm={searchTerm} />;
})}
<button type='button' onClick={() => handleOpen()}>Open modal</button>
</div>;
You should then change your Modal declaration as:
export default function Index({ isOpen, setIsOpen, text }) {
return (
isOpen && (
<div className='modalContainer'>
<div className="modal">
<div className="close">
<button onClick={()=>{
setIsOpen(false)
}}>close</button>
</div>
{text}
</div>
</div>
)
)
}
I am trying to convert the HTML/Javascript modal to React js.
In Reactjs, I just want to open the modal whenever the user clicks the View Project button.
I have created a parent component (Portfolio Screen) and a child component (Portfolio Modal). The data I have given to the child component is working fine but the modal opens the first time only and then does not open. Another problem is that the data does not load even when the modal is opened the first time.
Codesandbox link is here.
https://codesandbox.io/s/reverent-leftpad-lh7dl?file=/src/App.js&resolutionWidth=683&resolutionHeight=675
I have also shared the React code below.
For HTML/JavaScript code, here is the question I have asked before.
How to populate data in a modal Popup using react js. Maybe with hooks
Parent Component
import React, { useState } from 'react';
import '../assets/css/portfolio.scss';
import PortfolioModal from '../components/PortfolioModal';
import portfolioItems from '../data/portfolio';
const PortfolioScreen = () => {
const [portfolio, setportfolio] = useState({ data: null, show: false });
const Item = (portfolioItem) => {
setportfolio({
data: portfolioItem,
show: true,
});
};
return (
<>
<section className='portfolio-section sec-padding'>
<div className='container'>
<div className='row'>
<div className='section-title'>
<h2>Recent Work</h2>
</div>
</div>
<div className='row'>
{portfolioItems.map((portfolioItem) => (
<div className='portfolio-item' key={portfolioItem._id}>
<div className='portfolio-item-thumbnail'>
<img src={portfolioItem.image} alt='portfolio item thumb' />
<h3 className='portfolio-item-title'>
{portfolioItem.title}
</h3>
<button
onClick={() => Item(portfolioItem)}
type='button'
className='btn view-project-btn'>
View Project
</button>
</div>
</div>
))}
<PortfolioModal portfolioData={portfolio} show={portfolio.show} />
</div>
</div>
</section>
</>
);
};
export default PortfolioScreen;
Child Component
import React, { useState, useEffect } from 'react';
import { NavLink } from 'react-router-dom';
const PortfolioModal = ({ portfolioData, show }) => {
const portfolioItem = portfolioData;
const [openModal, setopenModal] = useState({ showState: false });
useEffect(() => {
setopenModal({
showState: show,
});
}, [show]);
return (
<>
<div
className={`portfolio-popup ${
openModal.showState === true ? 'open' : ''
}`}>
<div className='pp-inner'>
<div className='pp-content'>
<div className='pp-header'>
<button
className='btn pp-close'
onClick={() =>
setopenModal({
showState: false,
})
}>
<i className='fas fa-times pp-close'></i>
</button>
<div className='pp-thumbnail'>
<img src={portfolioItem.image} alt={`${portfolioItem.title}`} />
</div>
<h3 className='portfolio-item-title'>{portfolioItem.title}</h3>
</div>
<div className='pp-body'>
<div className='portfolio-item-details'>
<div className='description'>
<p>{portfolioItem.description}</p>
</div>
<div className='general-info'>
<ul>
<li>
Created - <span>{portfolioItem.creatDate}</span>
</li>
<li>
Technology Used -
<span>{portfolioItem.technologyUsed}</span>
</li>
<li>
Role - <span>{portfolioItem.Role}</span>
</li>
<li>
View Live -
<span>
<NavLink to='#' target='_blank'>
{portfolioItem.domain}
</NavLink>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default PortfolioModal;
You don't have to use one useState hook to hold all your states. You can and I think you should break them up. In the PortfolioScreen component
const [data, setData] = useState(null);
const [show, setShow] = useState(false);
I changed the function Item that is used to set the active portfolio item to toggleItem and changed it's implementation
const toggleItem = (portfolioItem) => {
setData(portfolioItem);
setVisible(portfolioItem !== null);
};
You should use conditional rendering on the PortfolioModal, so you won't need to pass a show prop to it, and you'll pass a closeModal prop to close the PortfolioModal when clicked
{visible === true && data !== null && (
<PortfolioModal
data={data}
closeModal={() => toggleItem()} // Pass nothing here so the default value will be null and the modal reset
/>
)}
Then in the PortfolioModal component, you expect two props, data and a closeModal function
const PortfolioModal = ({ data, closeModal }) => {
And the close button can be like
<button className="btn pp-close" onClick={closeModal}>
...
I am working on a React project, In my project I have two components those are App and Child.
The app is Parent component and child is Child component.
Now I Changed state in Child component when I click the button on Child component.
Now my goal is how to pass latest state of the Child component for a Parent component button.
I am not getting how to do this, please help me
This is App.js
import React from 'react';
import './App.css';
import Child from './Child/Child';
function App() {
return(
<div className='container'>
<div className='row'>
<button className='btn btn-primary'>Click here</button>
<Child></Child>
</div>
</div>
)
}
export default App
This is Child.js
import React, { useState } from 'react';
import './Child.css';
function Child() {
const [color, setColor] = useState('yellow');
const [textColor, setTextColor] = useState('white');
return (
<div className='container'>
<div className='row'>
<button style={{ background: color, color: textColor }}
onClick={()=>{setColor("black");setTextColor('red')}}className='btn btn-danger mt-5'>Click here</button>
</div>
</div>
)
}
export default Child
If you feel that I am not clear with my doubt, please put a comment.
Thank you.
You can not pass data from children to parent, just store data in parent and pass it to children like below
function App() {
const [color, setColor] = useState('yellow');
const [textColor, setTextColor] = useState('white');
return (
<div className='container'>
<div className='row'>
<button className='btn btn-primary'>Click here</button>
<Child
color={color}
setColor={color => setColor(color)}
textColor={textColor}
setTextColor={textColor => setTextColor(textColor)}
/>
</div>
</div>
)
}
export default App
import React from 'react';
import './Child.css';
function Child(props) {
const {color, setColor, textColor, setTextColor} = props;
return (
<div className='container'>
<div className='row'>
<button style={{ background: color, color: textColor }}
onClick={()=>{setColor('red');setTextColor('black')}}className='btn btn-danger mt-5'>Click here</button>
</div>
</div>
)
}
export default Child
define a function in parent component to
receive an argument i.e., child state here as per you question
pass this function as a prop to the child component
call this function from child component before or after setting the its state, as needed in your context.
I have used this method many a times while building react apps.
Please accept this as answer if it helps you out.
If your Child component has complex logic that you don't want the Parent to be bothered with you can pass a callback from Parent to the Child:
function Child({ onColorChanged }) {
//The disadvantage of this is that you can't pass in
// default values for color and textColor from Parent
const [color, setColor] = React.useState('yellow');
const [textColor, setTextColor] = React.useState('white');
//When color or textColor changes call the onColorChanged
// callback/event handler
React.useEffect(
() => onColorChanged({ color, textColor }),
//the onColorChanged callback/event handler is
// a dependency of this effect, that is why
// Parent uses useCallback so it won't change
// when parent re renders
[color, textColor, onColorChanged]
);
return (
<div className="container">
<div className="row">
<button
style={{ background: color, color: textColor }}
onClick={() => {
//some complicated logic you don't want in the
// parent
setColor('black');
setTextColor('red');
}}
className="btn btn-danger mt-5"
>
Click here
</button>
</div>
</div>
);
}
function Parent() {
const [state, setState] = React.useState();
const onColorChanged = React.useCallback(
color => setState(old => ({ ...old, color })),
[]
);
console.log('state is now:', state);
return (
<div className="container">
<div className="row">
<button className="btn btn-primary">
Click here
</button>
<Child onColorChanged={onColorChanged}></Child>
</div>
</div>
);
}
ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
If Child does not have complicated logic that you don't want in Parent you can just have Parent manage the state and pass a callback when something changes.
const colors = ['yellow', 'gold', 'black', 'white'];
function Child({ setColor, color: { color, textColor } }) {
return (
<div className="container">
<h1 style={{ background: color, color: textColor }}>
Hello world
</h1>
<label>
color
<select
value={color}
onChange={e => setColor('color', e.target.value)}
>
{colors.map(c => (
<option value={c} key={c}>
{c}
</option>
))}
</select>
</label>
<label>
text color
<select
value={textColor}
onChange={e =>
setColor('textColor', e.target.value)
}
>
{colors.map(c => (
<option value={c} key={c}>
{c}
</option>
))}
</select>
</label>
</div>
);
}
function App() {
const [state, setState] = React.useState({
color: 'yellow',
textColor: 'white',
});
const setColor = React.useCallback(
(key, value) =>
setState(old => ({ ...old, [key]: value })),
[]
);
return (
<div className="container">
<div className="row">
<Child setColor={setColor} color={state}></Child>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have this presentational component that includes a LoginForm which uses redux connect... when i try to see if the component is there by using wrapper.debug(), instead of the component i see: <Connect(Component) />
What do i have to do in order to see the actual LoginForm and test its length?
This is my component:
const LoginSection = ({ intl }) => (
<div className={styles.loginSection}>
<div className={styles.wrapper}>
<div className={styles.form}>
<p className={styles.title}>
<FormattedMessage
id="Dashboard.login.title"
defaultMessage="Login to an account"
/>
</p>
<LoginForm />
<p className={styles.createAccountWrapper}>
<span className={styles.dontHaveAccount}>
<FormattedMessage
id="Dashboard.login.subline"
defaultMessage="Dont have an account?"
/>
</span>
<a
className={styles.createAccount}
href={`${localeToDomainMap[intl.locale]}/register`}
>
<span className={styles.createOneHere}>
<FormattedMessage
id="Dashboard.login.createAccount"
defaultMessage="Create one here."
/>
</span>
</a>
</p>
</div>
</div>
</div>
);
and this is my test:
const setup = (newProps) => {
const props = {};
const wrapper = shallow(<LoginSection {...props} />);
return {
wrapper,
props,
};
};
describe('LoginSection', () => {
test('that it contains LoginForm', () => {
const { wrapper } = setup();
console.log(wrapper.debug());
expect(wrapper.find('.loginFrom')).toEqual(1);
});
});
and this is the result of wrapper.debug():
<div className="loginSection">
... other stuff here ...
<Connect(Component) />
... other stuff here ...
</div>