react native useState become empty when other state change - javascript

I have state like this
const [username,setUsername] = useState("")
const [password,setPassword] = useState("")
const [page,setPage] = useState("")
there is only one text input in entire page
in page 1 with prev and next bottom buttons
enter user name
in page 2 with prev and next bottom buttons
enter password
but when I move from page1 to page 2 or vice verse text input field become empty.
I am just hiding textinput according to page value

If these states are part of your Page1, whenever you are switching to Page2 you are unmounting Page1 and lifetime of states is till the time Page1 is mounted. Next time you are opening Page1 that is complete new fresh Page1.
If you want states should be persisted even on unmounting of pages you can go with following approaches:
1- Lift the state up
keep the states to parent component and pass the values/setter functions to the page.
const Dashboard=()=>{
const [username,setUsername] = useState("")
const [password,setPassword] = useState("")
const [page,setPage] = useState("")
const [activePage,setActivePage] = useState(0);
return(<div>
{activePage===0?<Page1 username={username} setUserName={setUserName}/>:null}
{activePage===1?<Page2 password={password} setPassword={setPassword}/>:null}
<button onClick={()=>{setActivePage(value=>value-1)}}>PREV<div/>
<button onClick={()=>{setActivePage(value=>value+1)}}>NEXT<div/>
</div>)
}
This way you are not unmounting parent component so state will not be on page changing.
2- Use any central state management library (redux/mobx/context)

The state will NOT stay alive longer then your component (I mean, whenever you change current page, the previous page is destructed).
What you seem to be aiming for can be called "persistent" state, or Application-wide state.
Redux is one of such persistent state implementions:
https://redux.js.org/introduction/getting-started

Related

React input value persists across modal re-renders, even though state is updated correctly. Why?

Sandbox - https://codesandbox.io/s/xenodochial-rain-4cl4iy?file=/src/App.js
I have a table as below:
When I click the 'edit' button it opens up a modal like below where I can then edit the input fields (onChange listener updates state):
Once I click 'save', it makes a 'fetch' call to save the data to backend and then closes the modal. If I click 'edit' on any other row the changed field is persisted as below:
Inspecting the element and looking at the state the values are correct:
Background on the code:
I am passing in the row's data as a prop to this modal
In the modal I'm using useEffect to re-render when the prop gets updated (when a different row's 'edit' button is pressed)
The props are being passed correctly, the state is being set correctly and only on changing the value of the input does the new value persist across modals. I'd like to fill the value of input from the props every time a new modal is opened.
Below are code snippets:
Passing data as a prop:
<EditConnectionModal connection={connection} setConnection={setConnection} initials={initials} getConnections={getConnections} />
Input:
<header class="form-floating">
<input class="border rounded form-control form-control-lg text-light bg-dark-2" type="text" id="name" placeholder="Name" defaultValue={name} onChange={e => setName(e.target.value)}/>
<label class="form-label text-start text-white-50" for="name">Full Name</label>
</header>
States and useEffect:
const [name, setName] = React.useState("")
const [email, setEmail] = React.useState("")
const [company, setCompany] = React.useState("")
const [website, setWebsite] = React.useState("")
React.useEffect(() => {
setName(connection.name)
setEmail(connection.email)
setCompany(connection.company)
setWebsite(connection.website)
}, [user, isAuthenticated, connection])
I was able to figure out what was wrong.
I was using bootstrap actions directly (data-bs-toggle, data-bs-dismiss, etc.) to invoke actions like open/close a modal. This interfered with the react event handler system and cause unexpected bugs.
In this specific case, the modal was being rendered on page load and NOT when the modal was opened. Hence it was being fed wrong props, hence overwriting the textbox with an unexpected value.
SOLUTION: Use state variables and react components to create and handle events like open/close a modal.
This is probably a simple and obvious answer but I'm new to react and this was an important lesson to learn the hard way.

React- Want to keep random options in a quiz app but the page keeps re-rendering upon using the button click

I have tried to keep this code as simple as possible to test the behaviour that is happening in react app component.
ISSUE: I have used random number generator to get a value and then divide by 2, to get remainder of 0 or 1, there are two buttons and the text in it would be displayed basing on the remainder. However, there is an onClick function to both buttons and upon clicking sometimes the text value in the button interchanges, which happens because the value of 0 or 1 changes upon clicking the button. Does the app component re-render from line0 upon clicking the button?, if not why does initially it takes in a value(0/1) and then might change upon click of a button ?. Images of the issue have been added for better understanding.
Here is the code:
import { useState } from 'react';
import './App.css';
function App() {
const i = Math.floor(Math.random() * 9);
const index = i%2;
const a ="button1"
const b= "button2"
const [image,setImage] = useState(false);
return (
<div className="App">
<h1>{index}</h1>
<button onClick={()=>setImage(true)}>{(index===0)?(a):(b)}</button>
<button onClick={()=>setImage(true)}> {(index===0)?(b):(a)} </button>
</div>
);
}
export default App;
Case0 on top[before pressing button] :
Case1 on top[I have pressed button1 from first case] :
I want the buttons to be random and also to stay that way after I have clicked the button. Any insights on this will be appreciated.

How to get React state to only change one item being returned in a .map?

It seems as though the way I'm writing my code below, when setLoading==true, it is changing all of my buttons to the loading state (true) when I only want the one being clicked to be changed. To further explain, I am simply displaying a spinner on the button when loading==true. Any idea as to how I can get this to behave properly? I figured it was a key issue, but that isn't the case, as I have a unique key for every element being returned.
Thank you all very much!
//Function called to set the state
const [loading, setLoading] = useState(false);
exampleArray.map((exampleObject, index) => {
return(
<div className={resulStyle.result} key={exampleObject.hash}>
<button key={exampleObject} onClick = {() => {router.push(`/queryFamily/${exampleObject.hash}`); setLoading(true);}}>{loading ?
<div className="spinner-box">
<div className="pulse-container small">
<div className="pulse-bubble pulse-bubble-1"></div>
<div className="pulse-bubble pulse-bubble-2"></div>
<div className="pulse-bubble pulse-bubble-3"></div>
</div>
</div>
: "View Pricing"}</button>
</div>
</div>
)
})
Capture the id/unique identifier of the button that is clicked as currentButtonLoading (or whatever): when mapping, see if that unique identifier === currentButtonLoading, then use your loading state to only impact that singular button.
Since loading is a variable set on state level it will be taken for all the buttons you render.
Why don't you use another state variable
const [currentButtonIndex, setCurrentButtonIndex] = useState();
And then on click set
setCurrentButtonIndex(index)
And in condition use
index===currentButtonIndex && loading
Well yes, and you should expect that to be the case. Here you have one component and you are keeping a string value as the state. If you change this state to true, React will render all your buttons with the loading state.
The solution is to create a component for your button and keep the state there and use that component here.
Example for that button component would look like this:
function MyButton() {
const [loading, setLoading] = useState(false);
return loading ? <Spinner /> : <button onClick={() => {your_thing; setLoading(true);}}>Something!</button>
}

Next.Js - useState is resetting dropdown values

I am creating a shopping page. I am keeping a JSON to store the product details. I have created the product as a component and using it in the shopping page. For each product I am keeping a drop down to select the quantity (0-5, default value is 0).
Whenever a drop down value change happens, I am making a call back to the parent which is the product page where I am updating the total count. I am using useState hook to update the total. The issue is that when I call the setState, the drop down is not showing the selected value, but the default one (My strong guess is that the drop downs are getting reset. When I remove the setState call, the drop downs work fine).
I am using react-dropdown for implementing drop down.
Parent Component:
const [total,setCartTotal] = useState(0)
const calculateTotalCartValue = (count) => {
setCartTotal(total+count)
}
// Adding the child Component
<Cartitem
parentCallback={calculateTotalCartValue}
/>
Child Component:
const calculateTotal = (event) => {
console.log(event) // This is properly printing the selected drop down details
parentCallback(2) // for testing I am passing value 2
}
// Drop down
<Dropdown
options={options} // I have a list of options
value={defaultOption}
onChange={calculateTotal}
/>

React - prevent re-rendering component if redux state is changed

I have some list in my application - there are screens like
ListScreen
CreateItemScreen
EditItemScreen
So firstly user goes to ListScreen, he can click "add item" and goes to CreateItemScreen. If he wants to delete item he needs to go to EditItemScreen and there is placed "Delete" button.
Items are stored in redux state - so when user creates item it's gonna be stored in redux. If user edits it - it's gonna be edited in redux. If he wants to delete item it needs to be deleted in redux.
When user click "Delete" system deletes it and redirect user back to ListScreen. Button system triggers delete item redux action, item is deleted and component is re-rendering - because redux state was changes so component's gonna be re-rendered. After it redirect is triggered(react-router-dom). But before redirect is triggered error appear. Because item is already deleted and screen is trying to take some item props.
Component looks like:
export const EditItemScreen = ({}) => {
const { itemId } = useRouteMatch().params;
const item = useSelector(getItemSelector(itemId));
const history = useHistory();
const dispatch = useDispatch();
const handleDeleteClick = () => {
history.replace('listPath');
dispatch(deleteItem(itemId));
};
return (
<div>
<h1>{item.title}</h1>
<form>...form</form>
<div>
<button onClick={handleDeleteClick}>
Delete
</button>
</div>
</div>
);
};
When user click "Delete" there is error which tells me that can't get title from undefined(because item is already deleted).
Can I prevent this last re-rendering? Just execute redirect before delete item and don't go back to this screen and don't re-render it?
Have you tried to do the dispatch before returning to the previous screen?
dispatch(deleteItem(itemId));
history.replace('listPath');
You want to leave the current component once everything is done so i think this should work.
You can try conditional rendering based on whether item.title is defined.

Categories

Resources