So I have a React job interview and have this piece of code in my assignment to close and modal box:
const App = (): ReactElement => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const renderApp = (): ReactElement => {
if (isOpen) {
return <FeedbackForm onClose={() => setIsOpen(false)} />;
}
return <button onClick={() => setIsOpen(true)}>Open modal</button>;
}
if (isOpen) {
return <>
<div className='App'>
<FeedbackForm onClose={() => setIsOpen(false)} />
</div>
</>
}
return <>
<div className='App'>{renderApp()}</div>
}
export default Feedback;
So here I have an App component that has a Modal component and a simple hook that has a boolean value that indicates if the modal is open or not. The modal starts off as closed, so the initial value is false. The button to open the modal is separate from the button that has to close the modal. The button to close the modal is within the Modal component while the button to open it is in the App component. Because they're both separate buttons, they can explicitly set the value to either true or false.
Now, on this topic, I received this question from the code reviewer:
Could you explain the potential issue of the following code?
const [isOpen, setIsOpen] = useState(false)
const toggle = () => setIsOpen(!isOpen);
I can't exactly see the problem in this snippet. I've tried running it with a button that calls toggle() and I see it updating the state perfectly fine. What is the potential issue the interviewer is talking about here?
In the toggle function, we are setting the state based on the current state value. React performs updates in batches and it is a possibility that when we run toggle() multiple times, the state is not updated for each subsequent run. So, to make sure that we don't lose the state updates from the previous runs, we can do something like the following:
const toggle = () => setIsOpen((prevIsOpen) => !prevIsOpen);
Now, in your scenario, it might not happen because we are showing/hiding modal based on toggle click which changes the views completely, but we can't be sure and can't take chances for production deployment. If it were something else, like showing/hiding of expansion panel, sidebar, etc. then the issue would be easily visible if you clicked toggle button simultaneously, with minimal delay between clicks.
Related
I am trying to change my URL after a modal is clicked.
I had added an extra onClick to the button which called the modal, this was to a function - in that function I added some console logging. I could see the logging, but the URL didn't change.
The (original) button code is:
<button className='buttonCheck' onClick={checkAnswer}>CHECK MY ANSWER</button> <CheckAnswerModal showModal={showCongratsModal} onClose={() => setShowCongratsModal(false)} videoMessage={showCongratsURL} content={showWindowContent} size='med'/>
And the modal
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
function CheckAnswerModal({showModal = false, onClose = () =>{}, videoMessage, content, size}) {
return (
<Modal
size={size}
show={showModal}
onHide={onClose}
backdrop="static"
keyboard={false}
>
<Modal.Body>
{videoMessage ? <video src={videoMessage} controls autoPlay> </video>: <div><center>{content}</center></div>}
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={onClose}>
Close
</Button>
</Modal.Footer>
</Modal>
)
}
export default CheckAnswerModal
Originally, I had added a new function to the calling page:
function GoHome() {
console.log("redirecting")
<Redirect to='/' />
}
and added this to the button onClick, I could see the logging, but no URL changing. I've done a bit of looking about and I am pretty sure this is not working as the modal is on screen. To get around this, in the GoHome() I even added a conditional (if the showModal is false, then do the logging)
I've seen some posts which talked about unmounting the component (now - this is something new to me, especially as I don't call any mount component explicitly.)
Am I missing something fundamental with redirect? Or can someone point me at what I am doing wrong (the redirect feels a little "hacky" just now, I need to redo a whole component I think, but this would work for now)
You have to install react-router-dom if you have not installed yet.
Then import it.
import {useNavigate} from react-router-dom
then call it inside a function like:
const navigate = useNavigate()
then in your onClose() function use navigate like:
navigate("/")
sorry for my English
Rather than trying to be smart, I simply declared history at the start and then in my onClose added history.push and it worked.
I am using React Native Material and i would like to use "loading" when a button is clicked. When the button is not clicked, it should only display the button.
Is it also possible when loading is displayed, it will disappear after 5 seconds or when i navigate to a different page?
I have tried to use an if statement when onPress is clicked to display loading but this displays an error.
https://www.react-native-material.com/docs/components/button
Code:
<Button
title="Submit Answers"
onPress={CalculateTotal}
loading
/>
Create a state variable for loading and set it false. So that whenever navigating to the component from another page, that will disable the loading.set loading true on button click and add a timeout for disabling it.
const [loading, setLoading] = useState(false);
const CalculateTotal =()=>{
setLoading(true);
setTimeout(()=>{
setLoading(false);
},5000)
}
<Button
title="Submit Answers"
onPress={CalculateTotal}
loading={loading}
/>
You need to create a loading state and change that state according to button press ex:
const [loading, setLoading] = useState(true);
return (
<Button
onPress={() => setLoading(!loading)}
title="Submit Answers"
onPress={CalculateTotal}
loading={loading}
/>
)
My function call takes some time to produce display, if any other button is clicked the result is overlapped and that is not desired. I need to disable all toggle buttons until one function call is complete, including reset button. Also, please can anyone add how do I display my function runtime on render screen. I'm getting the time in console window, I need to display it on screen below my div.
return (
<div>
<button onClick={() => this.resetfunc()}>Reset</button>
<button onClick={() => this.func1()}>Function 1</button>
<button onClick={() => {const start = performance.now();
this.func2();
const end = performance.now();
console.log(end-start);}}>Function 2</button>
<button onClick={() => this.func3()}>Function 3</button>
</div>
);
React always renders your current state (in a broad sense). So, if you want something to change, you have to change your state.
For example, you can have "working" state. In this state your buttons would be disabled (generally bad idea from UX point of view). And then, in "not_working" state all buttons would be enabled. Your goal is to switch your state when needed.
And for time your function worked - state again. If you want render something, you have to either hardcode it (like "Function 2" text), or put into state (in a broad sense).
Try adding a state for tracking if data is processing. The same can be used after the data is set.
const [processing, setProcessing] = useState(false)
When clicking a button,
<button disabled={this.processing} onClick={() => (this.setProcessing(true);this.resetfunc())}>Reset</button>
Also don't forget to reset it in your function call (Or keep it hanging if you want the buttons permanently disabled)
const resetfunc = () => {
// Do something cool here
this.setProcessing(false)
}
I'm using a Dialog component from Material-UI which, for the most part, is working correctly. However, if I click away from the Dialog, the Dialog will disappear (as expected) but sometimes, it remains in the DOM with its opacity set to 0, and I can't click anything else since the Dialog is in the way. This is a small sample of my code:
const [openDialog, setOpenDialog] = React.useState(false);
React.useEffect(() => {
// Get data for ReactTable
}, []);
return(
<div>
// Other components
<Button color="white" onClick={() => setOpenDialog(true)}>
Open Dialog
</Button>
// Other components
<Dialog open={openDialog} maxWidth="md" onClose={() => setOpenDialog(false)}>
// ReactTable and close button
</Dialog>
</div>
)
This bug doesn't always occur which makes it tricky to debug. I've only been using React for about a month, but I'm wondering if it's a state problem, or maybe some sort of race condition. Any suggestions?
Edit: This also occurs when a DropzoneDialog appears, to upload a file.
This also works:
<Dialog className={openDialog ? "" : classes.displayNone} open={openDialog} maxWidth="md" onClose={() => setOpenDialog(false)}>
// ReactTable and close button
</Dialog>
where in the styles file you have:
displayNone: {
display: "none"
}
In case anyone else has this same issue, I found the answer:
Elsewhere in the app, useEffect() was stuck in a loop and running extremely frequently which slowed the app down, causing this problem.
I have a button in my Header component. When it is clicked, it calls a toggleNav function stored in my context.js. This function changes the state of isNavOpen from false to true. The navgiation then opens. There is no CSS in my project that should allow this behavior. I also don't see any JS code that should allow this behavior either. Could someone tell me what code allows my navigation to open and close?
My codesandbox
This is down to the basic way that React works, when you change the state of a component, it re-renders itself with the new values you've set into state.
Specifically it's this bit of Header.js:
{context.state.isNavOpen && (
<div className="js-nav nav">
...
When the component renders the first time, context.state.isNavOpen is false, and false && anything is still false, so javascript ignores the code after the &&. That means it skips over the menu code.
The second time it renders, after you update the state which is pushed to context and then passed to <Header> as a prop (!), the component re-renders with your menu code.
If you use your browser's dev tools to inspect the DOM before and after you click the button, you'll find that the menu isn't hidden and shown, but rather when you don't see it, it's gone from the DOM altogether.
It's react feature whenever state changes component re-renders
same thing happening here
{context.state.isNavOpen && (
isNavOpen is toggling (true to false), (false to true)
for example - you can check it simply
class Toggle extends React.Component {
state = {
visibility: false
}
toggleVisibility=()=>{
this.setState(prev=>({visibility:!prev.visibility}))
}
render() {
const {visibility} = this.state;
return (
<div>
<button onClick={this.toggleVisibility}>Click Me</button>
<h3>{visibility?'Welcome':''}</h3>
</div>
);
}
};