How to handle React props correctly - javascript

I posted this here because I am relatively new to React and didn't know what exactly should I google. In my React project, I have a kendo grid that has a custom column named OPTIONS, like this:
<Grid onDataStateChange={onDataStateChange}
data={result}
{...{skip:0, take:13}}>
<GridColumn cell={CommandCell} title="Options"/>
<GridColumn field="session_id" title="Session" filter='text'/>
<GridColumn field="sn_zag_id" title="Service" filter='text'/>
The Option column is defined like this:
const [visible2, setVisible2] = useState(false);
const [snZagId, setSnZagId] = useState();
const toggleDialogPrilog = (props) => {
setVisible2(!visible2);
setSnZagId(props.dataItem.sn_zag_id)
}
const CommandCell = (props) => <Options {...props}/>
const Options= (props) => {
return <td className="k-command-cell">
<div style={{marginTop:'2%'}}>
<Button style={{width:'8vw',marginTop:'2%'}}
onClick={()=>toggleDialogPrilog(props)}>
Add
</Button></>}
</div>
{ visible2 &&
<Dialog onClose={()=> toggleDialogPrilog()} title={"Add"} style={{width:'50%'}}>
<Prilog snZagId={snZagId}/>
</Dialog>
}
</td>;}
So, In the option column I have a button ADD that, when it's clicked, opens a Dialog with PRILOG component inside it. The grid that I am talking about is big, made up of pages of 13 rows. Everything works perfectly, so when I click on the Add button, the dialog is open with custom material for that row. But the thing is, if I open the console/inspect, I can see that when I click add, 13 dialogs are open at the same time:
I am aware to some point that when I click Add, all dialogs are rendered bcz I send props, but I don't know how to stop it. In other words, how can I modify my code so that only one(1) dialog opens when I click Add?

I managed to solve the problem somehow, but I don't know what exactly is the difference. Instead of putting the Options component in the same jsx file, I made another component named SessionOptions like this:
Session.jsx:
import SessionOptions from '../../Popup/SesijaOpcije';
...
const CommandCell = (props) => <SessionOptions props={props}/>;
...
SessionOptions.jsx:
...
export default function SessionOptions({props}) {
...
return <td className="k-command-cell">
<div style={{marginTop:'2%'}}>
<Button style={{width:'8vw',marginTop:'2%'}}
onClick={()=>toggleDialogPrilog(props)}>
Add
</Button></>}
</div>
{ visible2 &&
<Dialog onClose={()=> toggleDialogPrilog()} title={"Add"} style={{width:'50%'}}>
<Prilog snZagId={snZagId}/>
</Dialog>
}
</td>;}
And now it opens just one dialog. The only difference that I clearly see is in sending the props
//Before:
const CommandCell = (props) => <Options {...props}/>
//After:
const CommandCell = (props) => <SessionOptions props={props}/>;
The first one is property spread notation, and the second one is...? Can anybody explain the difference.
If anybody could clearify more.

Related

How to render a new popup every time I clicked Grid?

The problem is...
The first popup renders fine.
But when I try to render the second popup, it's not working.
A new popup is not invoked, the previous popup is refreshed.
I want to call a new popup when I clicked a cell in the grid.
my code is like this
const Main = () => {
const [isPopupOpen, setIsPopupOpen] = useState(false);
return (
<>
... other components (including grid)
{ isPopupOpen && <Popup />}
</>
)
};
when Grid is Clicked, 'isPopupOpen' is updated to true.
I use 'react-new-window' library, and this library use 'window.open()' ((https://github.com/rmariuzzo/react-new-window)
so I set different window names to call several popups.
but I can't solve the problem.
I try to set a state object that has a boolean value.
const [popupObj, setPopupObj] = useState({});
when the grid is clicked, popupObj updates like
{'cellA': true, 'cellD': true}
and a return statement is like
{popupObj[cellName] && <Popup /> }
but the result was the same.
what should I do to solve this problem?
I wrote an example for you. Hope it helps.
use popupIds state to store the popups that you want to open
use Set to toggle the popupIds in the addPopup click handler
import * as React from "react";
export default function App() {
const [popupIds, setPopupIds] = React.useState([]);
const addPopup = (popupId) => {
const set = new Set(popupIds);
if (set.has(popupId)) {
set.delete(popupId);
} else {
set.add(popupId);
}
setPopupIds(Array.from(set));
};
return (
<div className="App">
{["hello", "react"].map((popupId) => (
<div onClick={() => addPopup(popupId)}>{popupId}</div>
))}
{popupIds.map((popupId) => (
<Popup title={getPopupTitle(popupId)} />
))}
</div>
);
}
const getPopupTitle = (popupId) => `title for ${popupId}`;
const Popup = ({ title }) => <div>{title}</div>;
Here is a codesandbox that you can play with directly.
You need to add your popup in an array, so you can render many popup as you want, then you need to define in How much time you will remove a added popup from array or add a close button
Extra: you can configure in global state to access in all your application to your popups and you will have a component like this: https://www.npmjs.com/package/notistack

State messiness trying to open a dialog, yet allowing the dialog to close itself

I'm prototyping a new version of our application in React 18. I'm somewhat new to React and have stumbled upon a scenario that has a few different problems.
We need to open a modal/dialog when a user performs an action. They will click a button to edit data, that opens a dialog window with a form. When they close the dialog, the form data is passed back to the component which opened it.
In our old app, it would be something like const user = new UserModal(123)
I'm using BlueprintJS's Dialog component for this, but this issue is applicable to any library.
I'm writing a wrapper because all of our modals will have similar functionality so the props to the Dialog component will never change outside of whether it's open or not.
Here's a super basic example of this "wrapper" component:
export const Modal = ({ isOpen }: ModalProps) => {
const [isOpen2, setIsOpen] = useState(isOpen);
const handleClose = useCallback(() => {
setIsOpen(false);
}, []);
return (
<Dialog isOpen={isOpen2}>
<p>this is a dialog</p>
<Button onClick={handleClose} text="close" />
</Dialog>
);
}
Using this in the parent would look like this:
const Demo = () => {
const [isOpen, setIsOpen] = useState(false);
// some code calls setIsOpen(true) when we need to open the modal
return <Modal isOpen={isOpen} />;
}
This presents multiple problems:
A parent controller can trigger this dialog to open, but never close (interacting with the app is prevented while a modal is open)
The modal can close itself via an X or "Cancel" button
This leads to two useState invocations - one in the parent controller and one inside the modal. This doesn't work right by itself, because once the state is set in the controller, it can't update when the prop changes with more code
The parent controller would need to know when it closes so it can update it's own state value.
I really dislike having to put <Modal> elements in the parent jsx, I liked the new UserModal code but that might be a fact of life
Overall, this feels like a very wrong approach. How can I design this to be more "proper" and yet work the way I need?
you can pass your method from parent to child and call there and also you can use 1 state for manage modal status.
export const Modal = ({ isOpen, handleClose, closeCallBack }: ModalProps) => {
const handleCloseChild = () =>{
closeCallBack()
handleClose()
}
return (
<Dialog isOpen={isOpen}>
<p>this is a dialog</p>
<Button onClick={handleCloseChild} text="close" />
</Dialog>
);
}
and parent something like this
const Demo = () => {
const [isOpen, setIsOpen] = useState(false);
// some code calls setIsOpen(true) when we need to open the modal
const handleClose = () =>{
setIsOpen(false)
}
return <Modal isOpen={isOpen} handleClose={handleClose} closeCallBack={() => // do what you want on close modal or you just do this in side modal or even in handelClose function } />;
}

How to show a Modal once onShowMoreClick is clicked?

<OneProfileKeyCard
title="Qualification"
showMoreText="See all qualifications"
onShowMoreClick={() => console.log('show more')}
>
Creating, communicating, and implementing the organization&apos;s vision, mission, and overall direction Leading the development and implementation of the overall organization&apos;s strategy.
</OneProfileKeyCard>
import React from 'react'
import './OneProfileKeyCard.scss'
type Props = {
title: string
showMoreText: string
onShowMoreClick: () => void
}
export const OneProfileKeyCard: React.FC<Props> = ({
title,
showMoreText,
onShowMoreClick,
children
}) => (
<div className="one-profile-key-card">
<h3>{ title }</h3>
<div>
{ children }
</div>
<button type="button" onClick={onShowMoreClick}>
{ showMoreText }
</button>
</div>
)
could anyone help me to set up a modal? Im trying to set up a modal once onShowMoreClick is clicked that would turn the children(creating, communicating, and implementing the organization...) into a modal. So far it looks like this:
You will need to have a state-managed in the parent component of where the OneProfileKeyCard child component is called from.
Something like this
const Parent = () => {
const [modalOpen, setModalOpen] = React.useState(false)
return (
<div>
<h1>Demo</h1>
<OneProfileKeyCard
title="Qualification"
showMoreText="See all qualifications"
onShowMoreClick={() => setModalOpen(!modalOpen)}>
text ... text
</OneProfileKeyCard>
</div>
)
}
I'm not sure what else is within your components, but you'll then need a way to close the model, right now I have set the showMoreClick prop to open/close, but if that should open then set it to true and do a similar pass-through for a closing false function.

What's the gain of hiding a Modal instead of unmounting it?

The common example of modal usually goes like this:
import * as React from 'react';
import { Modal, Portal, Text, Button, Provider } from 'react-native-paper';
const MyComponent = () => {
const [visible, setVisible] = React.useState(false);
const showModal = () => setVisible(true);
const hideModal = () => setVisible(false);
const containerStyle = {backgroundColor: 'white', padding: 20};
return (
<Provider>
<Portal>
<Modal visible={visible} onDismiss={hideModal} contentContainerStyle={containerStyle}>
<Text>Example Modal. Click outside this area to dismiss.</Text>
</Modal>
</Portal>
<Button style={{marginTop: 30}} onPress={showModal}>
Show
</Button>
</Provider>
);
};
export default MyComponent;
My question is. Why is this the recommended usage instead of just unmounting the component when is not needed anymore? Something like this:
visible && (<Modal visible={true} onDismiss={hideModal} contentContainerStyle={containerStyle}>
<Text>Example Modal. Click outside this area to dismiss.</Text>
</Modal>)
Is there any pro or cons of doing it one way or another? Is there a particular or good reason I have to do it in the first("official") way?
Let me borrow this answer by jimfb to the same question on github repo of react:
Hiding via CSS is slightly faster, but it has the downside that it means your dom/react tree is bigger, which means your reconciliations are bigger (slower) and your app is using more memory - even when the tree is not visible. If you can't tell the difference between the two, in terms of performance, we would recommend unmounting (since then you're cleaning up your memory and keeping your tree small).

React: override internal components with custom component

I have a modal that is completely self contained. The modal is opened via going to the modal route and all the functionality to close the modal from button or outside clicks is within the modal component. Basically the modal is not controlled by any parent passing state. I was given a task of making the modals button customizable, meaning passing in a new button component, so we can add the modal to our lib instead of copy pasting the code in projects. Lol this seemed simple enough, and maybe it is and I am just overthinking this.
I cant paste the actual code but I can use a contrived example. This is a very simplified version of the modal, keeping in mind it opens via route so there's really no state and setState in the actual code. Also here is a fiddle
const ModalHeader = ({ onClose }) => {
return (
<div className="modal__header">
<button
className="modal__close-btn"
data-testid="modal-close-button"
onClick={onClose}
/>
</div>
);
};
const Modal = ({ children }) => {
const [state, setState] = React.useState(true);
const handleCloseOutsideClick = () => {
setState(false);
};
const handleCloseButtonClick = () => {
setState(false);
};
const renderModal = () => {
return (
<div className="modal-overlay" onClick={handleCloseOutsideClick}>
<div className="modal">
<ModalHeader onClose={handleCloseButtonClick} />
{children}
</div>
</div>
);
};
return state ? renderModal() : null;
};
const App = () => {
return (
<Modal>
<div>Modal Children</div>
</Modal>
);
};
ReactDOM.render(<App />, document.querySelector('#app'));
I tried a few things, initially I attempted to find a way to pass in a new header component containing a button. Then as I got into the code I realized what I was doing would lose the self contained functionality of the modal. My approach was along the lines of below but obviously the onClick would be an issue since invoking the close functionality is internal.
So I tried using cloneElement to add props within the component if the custom header was detected:
// inside modal component
React.useEffect(() => {
React.Children.map(children, (child: React.ReactElement) => {
if (child && child.type === ModalHeader) {
setHederFound(true);
}
});
}, []);
// inside modal render:
<div className={modalClasses} onClick={stopPropagation}>
{!headerFound ? (
<ModalDefaultHeader onClose={handleCloseButtonClick} />
) : (
React.Children.map(children, (child: React.ReactElement) => {
if (child && child.type === ModalHeader) {
return React.cloneElement(child, {
onClose: handleCloseButtonClick,
});
}
})
)}
{children}
</div>;
Obviously that did not work because there's no onClick in the custom button. Anyways I am thinking that I am over complicating this. I just need a way to pass in a custom button while leaving the functionality internal to the modal. Any assistance would be appreciated.
Thanks in advance.

Categories

Resources