How to update default value of MUI TextField? - javascript

I'm finishing up the final steps of my form however I have encounter an issue when trying to display the current name of the user in the defaultValue variable of the TextField from MUI.
If a value starts on ""/null or basically empty the defaultValue will stay empty doesn't matter how many times you update that value from ""/null to something, is there a way to fix that?
I have this:
{console.log(tempName)}
<TextField
required
margin="dense"
label='Nombre'
defaultValue= {tempName}
onChange={handleChangeName} />
tempName starts empty but then I update it in a useEffect I have that brings the data of the document of the user I'm log in atm, even after having a value the defaultValue stays empty/null/"".
There's something else I did notice though, if you use the user.displayName directly it does works but only until you refresh (because when you refresh user goes back to null and then like .2 segs is back to his value)
this is how it looks when I use user before refresh
since user brings both name and lastname (displayName, basically) I wanted to split it and all the user information is in a document :
const [tempName, setTempName] = useState("");
const [tempLastName, setTempLastName] = useState("");
const [tempEmail, setTempEmail] = useState("");
const [tempPhone, setTempPhone] = useState("");
const [tempIdType, setTempIdType] = useState("");
const [tempIdTypes, setTempIdTypes] = useState("");
useEffect(() => {
const userDoc = db.collection('usuarios').doc(user.uid);
userDoc.get().then(doc => {
if (doc.exists) {
const tempData = [];
const data = doc.data();
tempData.push(data);
setTempName(tempData[0].name)
setTempLastName(tempData[0].lastName)
setTempEmail(tempData[0].email)
setTempPhone(tempData[0].phone)
setTempIdType(tempData[0].id)
setTempIdTypes(tempData[0].idType)
setOldPassword(tempData[0].password)
}
});
}, [user])
This is how it looks in the firebase
Is that how is suppose to work?
I would have think that defaultValue will update to the value you are giving it... Thank you, I didn't find anything related with this on TextField documentation. All I know is that they add initialized values from the very beginning and not values that get "updated" with time, I just wanted to display the current information of the user in the form.

Have a look at controlled mode example, defaultValue doesn't work on subsequent renders, if you want to control and update the value, use value prop.
Default value is usually used in uncontrolled mode where the value is controlled by the DOM element, not react itself, and the only way to alter it is setup an initial value when it is first mounted. The value of the uncontrolled component can only be accessed (without using ref) when submitting the form or validating the value, if you want to update the state on the fly based on the value as the user types, use controlled mode.
value={value}
onChange={e => setState(e.target.value)}
what's the purpose of defaultValue then? if you can just use placeholders for stuff like "Name" and then use value instead of defaultValue
If you use a placeholder, the default value of that TextField won't be submitted in the form (probably not what you expect here).

Related

useEffect to set value of TextField not working

I'm attempting to use useEffect to set the initial value of a MUI TextField on load. The value is being pulled from a database. This works the majority of the time however in some cases the useEffect does not correctly update the value of the textfield and it is just blank.
My Question: How can I change my code to make sure that the data being pulled from useEffect always sets the initial value of a textfield on load?
const [introText, setIntroText] = useState();
useEffect(() => {
const fetchResults = async () => {
const result = await axios({
method: "GET",
url: "https://server.site.com/userData",
withCredentials: true,
});
setIntroText(result.data.introEssayText);
};
fetchResults();
}, []);
<TextField
onChange={(e) => setIntroText(e.target.value)}
value={introText}
onInput={handleUpdatedIntro}
/>;
"This works the majority of the time however in some cases the useEffect does not correctly update the value of the textfield and it is just blank". Make sure result.data.introEssayText is not empty for all use cases.
Other than that, having const [introText, setIntroText] = useState() would trigger the below warning for a normal input which I belive TextField would fall back to.
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
Insted use const [introText, setIntroText] = useState("") so the initial value of the input is "" instead of undifined.

React useState doesn't update even with useEffect added

Probably it is a classic issue with useState which is not updating.
So there is a tree with some checkboxes, some of them are already checked as they map some data from an endpoint.
The user has the possibility to check/uncheck them. There is a "cancel" button that should reset them to the original form.
Here is the code:
const [originalValues, setOriginalValues] = useState<string[]>([]);
...
const handleCancel = () => {
const originalValues = myData || []; //myData is the original data stored in a const
setOriginalValues(() => [...myData]);
};
...
useEffect(() => {
setOriginalValues(originalValues);
}, [originalValues]);
However, it is not working, the tree is not updating as it should. Is it something wrong here?
Just do the following, no need for ()=> the state will update inside the hook if called, plus change the constant it will cause confusion inside your code and protentional name clash later on, with the current state variable name, and also make sure your data are there and you are not injection empty array !!!! which could be the case as well !.
// Make sure data are available
console.log(myData)
// Then change the state
setOriginalValues([...myData]);

React + Formik - how to pass in new values and set form as dirty?

I have a Formik form in my React app and I have a specific scenario I can't seem to find a workaround for:
I have a toggle outside of my custom form component that essentially "sets everything in the form to false". My current solution is when that gets toggled, I update the props I'm passing to form component, and re-rendering:
In my Form component:
const [initialState, setInitialState] = useState(props.initialState);
useEffect(() => {
setInitialState(props.initialState);
}, [props.initialState]);
...
...
<Formik
enableReinitialize
initialState={initialState}
...
/>
This does correctly update my form with the new values, but it doesn't set the form to be dirty. I have logic in my form component based on whether it is dirty, and in this scenario I want the form to be considered dirty. I first tried to set each field to be touched or include each one in initialTouched. However, dirty is computed comparing current values to initialState, not whether fields have been touched, so my form here is considered "pristine" because it is literally the same as my (new) initial state.
What I'm looking for is either:
A way to pass in these new values as something other than initialState (ie somehow imperatively set values from outside <Formik />) that would cause dirty to be computed as true
A way to force my form to be dirty (it's a read-only property, but if there is another way to mimic it and force it to be true)
onSubmit={(values, { setSubmitting, resetForm }) => {
setSubmitting(true);
setTimeout(async () => {
console.log(values);
// it will set formik.isDirty to false
// it will also keep new values
resetForm({ values });
}, 100);
}}
Have you tried using the onReset property? That should allow you to pass values from any source you want.

Adding/deleting data into local browser storage using a button, and displaying it in a UI table (React)

I would like to have a react app that uses local storage to store data, and display that data in a table in the user interface (UI).
I want to be able to submit an entry into local storage by clicking a button (SUBMIT), and then be able to delete an entry in local storage by clicking another button (DELETE).
And whatever data is in local storage I would like it to be displayed in a small table in the UI even after the browser is refreshed.
I have used this tutorial (https://www.robinwieruch.de/local-storage-react#local-storage-in-react) as a basis for the local storage and provided the code I am using from that tutorial below. But in the tutorial, the data is submitted by typing into a box and having it displayed in a paragraph. And from the developer tools I can see this is only for one key value pair.
CODE:
import React from 'react';
const useStateWithLocalStorage = localStorageKey => {
const [value, setValue] = React.useState(
localStorage.getItem(localStorageKey) || ''
);
React.useEffect(() => {
localStorage.setItem(localStorageKey, value);
}, [value]);
return [value, setValue];
};
const App = () => {
const [value, setValue] = useStateWithLocalStorage(
'myValueInLocalStorage'
);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React with Local Storage!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
export default App;
From the tutorial, I believe data will be:
Submitted into local storage using localStorage.setItem('myData', data)
Displayed in the table using localStorage.getItem('myData')
Deleted from local storage/table using localStorage.removeItem('myData')or, localStorage.clear()
My guess is each one of the previous pieces of code will be in a a separate function that gets called in return().
I have attached below, what I am trying to create, specifically, what the UI will look like:
Submitting data to local storage is done with the SUBMIT button, while data is deleted from local storage using the DELETE button in the table, while everything that is displayed in the table is from local storage.
Let me know if more information is needed. There are so many ways to do this, and I honestly do not know what to do. For example, if I need to create a class with multiple functions in the class that do what I described above (e.g a function for submitting, another for deleting, and one for retrieving data from the table).
To store arrays in localstorage use JSON.stringify otherwise you will end up storing a comma separated string
So the code for the custom hook will need to be changed to use JSON.stringify and JSON.parse
const useStateWithLocalStorageArray = localStorageKey => {
const [value, setValue] = React.useState(
JSON.parse(localStorage.getItem(localStorageKey) || '[]' )
);
React.useEffect(() => {
localStorage.setItem(localStorageKey, JSON.stringify(value))
}, [value]);
return [value, setValue];
};
Here is the full source in Plunker - https://plnkr.co/edit/NuSBnLpPpoOmmEE6

How to update a field value after action dispatched with redux

I would like to populate a form after an ajax call with redux.
My case is pretty simple:
I have a simple user form (with only one text field for now), it's a react view bound to the state with connect().
I call a rest API to fetch the user.
When the api call is done, an action is dispatched with the user.
A reducer update the store state with the user.
I would like to populate/update the form with the retrieved values.
Solution 1:
If I set the value from the props like that:
const Field = ({ field, onFieldChange, value }) => (
<input
value={value}
onChange={(event) => { onFieldChange(field, event.target.value) }}
type="text"
/>
)
It works but I get this warning:
Field is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa).
I understand why I get this error as I should not use a component to display something and also be able to update it.
I also tried to use the defaultValue props but this is only used at the component creation (and we don't have the user yet). After the ajax call return, defaultValue cannot be called.
Solution 2:
Use redux-form with a custom plugin to update the form model each time the state get updated. I don't find this solution really clean but maybe I'm wrong.
I really thin that I'm going in the wrong direction and that it should exist a better way.
Does somebody already faced this kind of issue?
I encountered the same problem when I was trying to pass undefined as the input value.
To fix this, ensure that you are passing at least empty string to the input, not undefined
const Field = ({ field, onFieldChange, value }) => (
<input
value={value || ''} // <- add fallback value here
onChange={(event) => { onFieldChange(field, event.target.value) }}
type="text"
/>
)
Actually you might try to make your component statefull - store and manage value of input inside of it (they say it's ok).
Or if you really need this value in the store use redux-form, I have realy good experience of using it (you'll have to write less boilerplate code).
By the way, you will not have to use any custom plugin, you can use initialValues, see more here
The solution above will work for sure, but it doesn't seem to be nice.

Categories

Resources