Manually triggering onChange callback in React 18+ - javascript

The problem is that I'm unable to manually trigger onChange callback on input component in React. I have a custom 'file picker' which changes the input's value of new selected file path. I want to manually dispatch a 'change'/'input' event for this input.
Example case:
<input onChange={(e) => console.log(e.target.value)} />
const inputRef = /* ref of input above */
/* .. */
const newValue = 'path/test.ext';
inputRef.current.value = newValue;
// dispatch change event for inputRef.current to console log new value
I'd like to point out that I've already researched the subject. The newest solution I've could find is: https://stackoverflow.com/a/71340077/14175627
Sadly, this solution doesn't work anymore and I'm unable to find working one.

Related

Why my data is not loading back when I erase the searchTerm passed to Input field in reactJs?

I am making a search functionality into react that effectively looks for data from json-server for a match. I don't want to provide a debounced search to the input field, rather I want to trigger the search when "Enter" key is pressed. So i used onKeyPress prop from MUI's textfield, where I provided the logic to send the query to the server.
Please acknowledge my code as mentioned below -
imports...
export default function AppSearchBar ( ) {
// local state for searchTerm
const [ searchTerm, setSearchTerm ] = useState<string>('');
// using redux - action
const {loadedBooks} = useAppSelector(state => state.books);
const {loadedGames} = useAppSelector(state => state.games);
// these 'loadedBooks' and 'loadedGames' are of type boolean and are initially false (coming from my slices) and set to true when their requests are getting fulfilled.
const dispatch = useAppDispatch();
// useCallback
const fetchAllCategories = useCallback(() => {
setTimeout( async () => {
await dispatch(fetchBooksAsync( searchTerm )); // this is async thunks i created to fetch books into my bookSlice.ts file
await dispatch(fetchGamesAsync( searchTerm )); // this is async thunks i created to fetch books into my gameSlice.ts file
}, 500);
}, [ searchTerm , dispatch ]);
// effect when searchTerm mounts
/* useEffect(() => {
fetchAllCategories()
}, [ fetchAllCategories ]); */ // dependency as the function itself.
// I want this useEffect, but un-commenting this is not allowing my "handleSearchOnEnter" to come into the picture at all, but, I want that first load of all cars be automatic, and then when I write something to input, on pressing enter it should search, and finally when I wipe input field, it should return me back all the cards.
const handleSearchOnEnter = ( event : any ) => {
if ( event.key === "Enter" ) {
fetchAllCategories(); // this is wrapped inside of useCallBack and effect is produced using useEffect.
}}
return (
<Fragment>
<TextField
value = {searchTerm}
onChange = {( event : any ) => setSearchTerm(event.target.value)}
onKeyPress = { searchTerm !== "" ? handleSearchOnEnter : undefined } />
</Fragment>
)
}
Now, problem statement -
Whenever I load my window, all Books and Games are not loaded at all (if I remove useEffect() from code). They only loads when I press enter. But, I don't want this behaviour.
If I keep useEffect() - hook, then they behaves like debounce search and onChange of my text input field, they return the searched result.
What I want is as follows -
- Whenever I first loads the window, all products get loaded.
- Whenever I write something into the input field, then it shouldn't call (fetchFiltersAsync() - which is the API call for full-text search on Json-Server) until i press Enter key, only When I press enter, it should call the API and fetch the relevant results.
- After that, when I manually remove the searchedItem from input field (wiping it), all of my data should get returned. (i.e display all cards into UI)
What is Happening? -
Whenever My window loads, all of my data/cards are not getting loaded., until I presses enter key...cool
When I type something into input field, it fetches the searched results without even taking "Enter" (because of open useEffect() into the code)
When I remove a term from the input field, my data is not getting loaded automatically back to like as they were into first visit (all cards visible).
All controls are here only (into the code), I have to do something with searchTerm, so whenever searchTerm is not empty, then my handleSearchOnEnter() function should get called.
I mean, it should produce useEffect automatically, but only when a searchTerm is not being provided. If the searchTerm is being provided, then it should trigger handleOnEnterSearch()
I had the same issue that is described in the second Problem I solved it by adding in my project.
<form onSubmit={onKeyDownHandler}>
<TextField>{"Some Code"}</TextField>
</form>;
Also you can create an useState and giving it new Date will refresh your table better.
const onKeyDownHandler = (e) => {
e.preventDefault();
// if (searchTxt.length >= 3 || !searchTxt.length) {
dispatch(setSearchTxt(searchTxtTemp));
setTriggerSearch(new Date().getTime());
// }
};
But the bad sides of this code is when you remove everything from input you need to press enter again to refresh.

I want to clear input datepicker value on clicking clear button in react

When the value is set using defaultValue prop it is clearing the field but, not when used value prop. package details import { TextField} from '#material-ui/core';
The issues is caused because of the required property in the component, I removed it and it started working fine. check this code codesandbox, try adding and removing required property and click on clear button
Provided you do not have the control marked required, the onChange should fire on clear, handing you an empty string.
We also need to handle that case properly. Testing the date for validity and rejecting invalid dates by setting it to null perhaps.
With that change, make sure formatDateAndTime correctly handles the case in which the date is null, and so returns an empty string.
<TextField
type="datetime-local"
value={formatDateAndTime(this.state.editedValue.startDateTime) }
onChange={(date: any) => {
const selectedDate = new Date(date.target.value);
const sanitizedDate = isNaN(selectedDate) ? null : selectedDate;
this.setState((prevState) => ({
editedValue: { ...prevState.editedValue, startDateTime: sanitizedDate }
}));
}}
/>

React state won't update from within a useCallback

I am using the following code to render a Material UI AutoComplete field with options retrieved from an API. I would like to prevent re-rendering of the input field but the chosen country is used as a prop for the Country component which should be updated onChange. set_alpha3Code doesn't seem to update the state from within useCallback. How do I get around that?
let AC = memo(AutocompleteCountries)
function Show(props: {})
{
let [alpha3Code_, set_alpha3Code_] = useState<string>('gbr');
let onChange = useCallback((alpha3Code) => {
console.log(alpha3Code_);
set_alpha3Code_(alpha3Code);
}, []);
return (
<div>
<AC onChange={onChange}/>
{alpha3Code_ ? <Country cca3_={alpha3Code_}/> : null}
</div>
)
}
Two things jump out about that code:
onChange without value
Stale state
onChange without value
In the normal case, if you specify onChange with an input control, you have to specify value to tell the control what the current (updated) value is. The documentation for Material-UI's Autocomplete definitely suggests you need both:
Controlled states
The component has two states that can be controlled:
the "value" state with the value/onChange props combination. This state represents the value selected by the user, for instance when pressing Enter.
The same thing with a standard input prevents the input from ever changing. I haven't used the Material-UI Autocomplete, but I suspect it's similar.
Stale state
Your code is updating the value of alpha3Code_ (if onChange is called with a new value), but the console.log in that code looks at at an old one:
let onChange = useCallback((alpha3Code) => {
console.log(alpha3Code_); // <−−− Uses the *first* `alpha3Code_` only
set_alpha3Code_(alpha3Code);
}, []);
// ^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Because you haven't included
// `alpha3Code_` in these dependencies
But even though that console.log shows you outdeated information, the rest of the code is fine and will work. It will re-render the AC with the updated code.
If you want to see the alpha3Code_ used for rendering, put a breakpoint on the return and look at it in the debugger (or move the console.log outside the onChange handler to above the return).

React.js Using the same FORM for creating a NEW db object and EDIT various objects

I have a simple input field like this:
<TextField
required
variant="standard"
type="string"
margin="normal"
fullWidth = {false}
size="small"
id="orgName"
placeholder="Organisation Name"
label="Name"
name="orgName"
// defaultValue={orgData ? orgData.orgName : ""}
//inputRef={(input) => this.orgName = input}
value={this.state.orgName || ""}
onChange={this.handleChange("orgName")}
error={this.state.errors["orgName"]}
/>
I want to use the same input field for new and update? For new I just set the state to empty, and save the values. Which works fine. Now I have a select dropdown to edit the previously saved objects.
My problem is with editing, and I am tearing my head out trying to find the any way to do this. All these are the corresponding issues:
If i set the state from props - any edited changes are being reset
If i don't set the state from props, I get all blank fields, which is incorrect.
If I use defaultValue to load the form inputs from props, then its only called once. And it does not reload when I change the object to be edited.
If i just use onChange handler for, the form gets creepy slow, with many inputs on page
If I use refs, I am not able to reset the refs to reload the input when the object to be edit changes.
I have managed to make it work with componentWillReceiveProps, but it is deprecated, and react website is saying its dangerous to use it.
componentWillReceiveProps(nextProps) {
if (nextProps.orgData !== this.props.orgData) {
this.setState({
"orgName": nextProps.orgData.orgName,
"orgPath": nextProps.orgData.orgPath,
"orgAddress": nextProps.orgData.orgAddress,
"orgPhone": nextProps.orgData.orgPhone,
"orgEmail": nextProps.orgData.orgEmail,
})
}
}
So how can I actually create an editable form where the values have to be loaded from props for different instances from db, but they have to controlled by the state. There has to someplace where I have to check saying "hey if the props have changed, reset the state with the new props for edit???
This has been the most frustrating experience using react for me. How are there no examples anywhere on how to build a simple form to create new, and editable object using react and redux. It just seems overly complicated to do such a simple thing, the whole thing just sucks!
There has to someplace where I have to check saying "hey if the props have changed, reset the state with the new props for edit???
Yes you can use React.useEffect hook on the special prop or Array of props, then when that/those prop(s) change the internal hook function will be fire.
e.g. :
const MyComponent = (props) => {
let [myState,setMyState]= React.useState(null);
React.useEffect(()=>{
setMyState(props.prop1);
},[props.prop1]);
return ...
}

Why is event returned by event handler initially 'undefined'?

I'm building a simple React component and am confused about something. Here's the crux of the code:
const handleToggleButtonClick = (event) => {
console.log('handleToggleButtonClick', event.target.value);
if (event.target.value !== undefined) {
const newVal = (event.target.value === 'true');
setIsFirstButton(newVal);
}
};
return (
<ToggleButton value='true' onClick={handleToggleButtonClick}>
Sample Text
</ToggleButton>
)
When I add the React component to my app and run it, event.target.value is initially undefined, immediately followed by being true. Given that value is hardcoded to true, why would it ever be undefined?
take a look at the documentation https://react-bootstrap.github.io/components/buttons/#toggle-button-props I think there is a misuse of event handler in your components. If you want to use standalone togglebutton then you should listen onChange instead
<ToggleButton value='true' onChange={handleToggleButtonClick}>
It looks like this button has to toggle some state but your storing your initial state via target.value.
Why not use:
const [toggledState, setToggleState) = useState(true)
Then when you fire the event handler just update the state? E.g setToggleState(!toggledState). This will invert the state on every click.
The benefits here is that you don’t have to store state on the toggle then try and mutate it. Secondly you drive your state down your view. Rather than persist upwards and modify (with extra unneeded effort).

Categories