Before I ask my question: Yes I did read every other article about this but im basicly just stuck and can't figure out how to fix this.
So basically my rendering and console.log are one step behind my useState changes. The biggest problem visually and functionally is the dynamic button which doesn't enable/disable correctly. My code is:
import React, { useState, useEffect } from 'react';
import ApiCalls from "../../classes/apiCallsClass"
import useStyles from "./styles";
import { TextField, Select, Paper, Grid, MenuItem, Button } from '#material-ui/core';
import { withStyles } from "#material-ui/styles";
export default function TicketCreation() {
const [buttonDisabled, setButtonDisabled] = useState(true);
const [, setTick] = useState(0);
const classes = useStyles();
const [ticketname, setTicketName] = useState('');
const [description, setDescription] = useState('');
const [prio, setPrio] = useState('');
const [system, setSystem] = useState('');
const handleChangePrio = event => {
setPrio(event.target.value);
checkFormFilled();
};
const handleChangeDescription = event => {
setDescription(event.target.value);
checkFormFilled();
};
const handleChangeName = event => {
setTicketName(event.target.value);
checkFormFilled();
};
const handleChangeSystem = event => {
setSystem(event.target.value);
checkFormFilled();
};
const checkFormFilled = () => {
if (ticketname && description && prio && system) {
setButtonDisabled(false, function(){
setTick(tick => tick + 1);
});
} else{
setButtonDisabled(true, function(){
setTick(tick => tick + 1);
});
}
}
const handelButtonSubmit = event => {
if (ApiCalls.createTicket(ticketname, system, prio, description)) {
console.log("Created");
}
}
return (
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={4}>
<Paper className={classes.paper}>
<TextField id="standard-basic" value={ticketname} onChange={handleChangeName} label="Ticketname" fullWidth />
</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}>
<Select value={system} onChange={handleChangeSystem} displayEmpty fullWidth className={classes.selectEmpty}>
<MenuItem value="" disabled>
System
</MenuItem>
<MenuItem value={1}>Radar</MenuItem>
<MenuItem value={2}>Missles</MenuItem>
<MenuItem value={3}>Toilet</MenuItem>
</Select>
</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}>
<Select value={prio} onChange={handleChangePrio} displayEmpty fullWidth className={classes.selectEmpty}>
<MenuItem value="" disabled>
Priority
</MenuItem>
<MenuItem value={1}>Low</MenuItem>
<MenuItem value={2}>Medium</MenuItem>
<MenuItem value={3}>High</MenuItem>
</Select>
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
<TextField
value={description}
onChange={handleChangeDescription}
id="outlined-multiline-static"
label="Ticket description"
multiline
rows="4"
variant="outlined"
fullWidth />
</Paper>
</Grid>
<Grid item xs={12}>
<Button disabled={buttonDisabled} onClick={handelButtonSubmit} variant="contained" color="primary">
Create
</Button>
</Grid>
</Grid>
</div>
);
}
Don't mind the setTick usestate, I tried this in combination with a callback to fix the issue but it wasn't working.
My question basically is:
What do I need to do to enable my button instantly without delay? (and maybe other things I do wrong? first time using react hooks)
State setters (setSystem, etc.) are asynchronous. That means where you're doing things like setSystem(event.target.value); checkFormFilled() -- the new value of system, in this case, may not be updated by the time checkFormFilled runs. That's likely why you're seeing things "lag behind" the values.
What you should be doing is not calling checkFormFilled directly after your set state calls; instead, put checkFormFilled in a useEffect hook that depends on the form elements. That way, React will call your checkFormFilled function when any of those values are actually updated.
useEffect(() => {
checkFormFilled();
}, [ticketname, description, prio, system]);
Then your change handlers only need to worry about setting the values, not calling the form filled check, and everything is guaranteed to be up to date.
Related
I have a two div I want to send selected text to another div using onSelect event? Right now entire para sending to another div but I want to send just selected text. How can I do this?
Demo:- https://codesandbox.io/s/selected-text-send-to-another-div-using-onselect-0ccnrn?file=/src/App.js
My Code:-
import React from "react";
import { Box, Grid, TextField, Typography } from "#material-ui/core";
import { useState } from "react";
const SendSelectedText = () => {
const [label1, setlabel1]=useState('');
const [para, setPara]=useState('This is Old Para');
const handleClick = () => {
setlabel1(para);
};
return (
<>
<Box className="sendSelectedTextPage">
<Grid container spacing={3}>
<Grid item xl={6} lg={6} md={6}>
<textarea onSelect={handleClick}>{para}</textarea>
</Grid>
<Grid item xl={6} lg={6} md={6}>
<TextField
variant="outlined"
size="small"
label="Label One"
value={label1}
multiline
rows={3}
className="sendSelectedTextPageInput"
/>
</Grid>
</Grid>
</Box>
</>
);
};
export default SendSelectedText;
Thanks for your support!
All you need is use window.getSelection().
Here is solution
import React from "react";
import { Box, Grid, TextField, Typography } from "#material-ui/core";
import { useState } from "react";
const SendSelectedText = () => {
const [label1, setlabel1] = useState("");
const [para, setPara] = useState("This is Old Para");
const handleMouseUp = () => {
setlabel1(window.getSelection().toString()); // setting up label1 value
};
return (
<>
<Box className="sendSelectedTextPage">
<Grid container spacing={3}>
<Grid item xl={6} lg={6} md={6}>
// changed event to onMouseUp
<textarea onMouseUp={handleMouseUp}>{para}</textarea>
</Grid>
<Grid item xl={6} lg={6} md={6}>
<TextField
variant="outlined"
size="small"
label="Label One"
value={label1}
multiline
rows={3}
className="sendSelectedTextPageInput"
/>
</Grid>
</Grid>
</Box>
</>
);
};
export default SendSelectedText;
Sandboxlink
You have to use the selection
const handleClick = (e) => {
setlabel1(
e.target.value.substring(e.target.selectionStart, e.target.selectionEnd)
);
};
or
const handleClick = (e) => {
setlabel1(
para.substring(e.target.selectionStart, e.target.selectionEnd)
);
};
Based on this
sandbox
I'm trying to use Slider/Select to get user query parameters, which will make further changes to the URL (through handleChange) and make api calls through fetch hooks.
However, when I change the Slider value from 1 to 0.1, nothing happens, but if I change the slider value again to 0.1 to 0.2, it will return me the result of 0.1 ( therefore lagging by 1 click). Similar behavior is observed with the Select value.
Website here:https://thisorthatstockfrontend.herokuapp.com/rankStockSharpeFiltered
I don't have form control but after trying form control it didn't seem to fix the issue. I really do not want to have a submit button, any help is appreciated!
import React from 'react'
import { NavLink } from 'react-router-dom'
import { Button,InputLabel } from '#mui/material'
import { Typography,MenuItem } from '#mui/material'
import { DataGrid } from '#mui/x-data-grid'
import Slider from '#mui/material/Slider';
import { useEffect } from 'react'
import {FormControl} from '#mui/material';
import { useState } from 'react'
import { useFetch } from '../hooks/useFetch';
import { useForm,Controller } from "react-hook-form";
import Select,{SelectChangeEvent} from '#mui/material/Select';
import Grid from '#mui/material/Grid'
import { Box } from '#mui/system';
export default function StockListedFiltered()
{
const [values, setValues] = useState(
{
sharpeYear1: 1,
sharpeYear2: 5,
sharperatio1Cutoff: 1,
sharperatio2Cutoff: 1,
}
);
const [url,seturl]=useState('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
const handleChange = (propertyName) => (event) => {
console.log('hello')
event.preventDefault();
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values)
seturl('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
console.log(url)
};
const{data:stockPerformance ,isPending,error}=useFetch(url)
const columns=[
{field:'stockName', headerName:'ticker',width:200 },
{field:'years', headerName:'years' ,width:200},
{field:'SharpeRatio', headerName:'sharpe ratio',width:200},
{field:'AnnualReturn', headerName:'annual return',width:200 },
{field:'AnnualVolatility', headerName:'annual volatility',width:200 }
];
return (
<div>
<h2 style={{paddingTop:'3rem',textAlign:'center',paddingBottom:'2rem'}}> Filtered Stocks Ranked </h2>
<NavLink to="/rankStockSharpe">
<Button>
<Typography>All stock </Typography>
</Button>
</NavLink>
<NavLink to="/rankStockSharpeFiltered">
<Button>
<Typography>Filtered </Typography>
</Button>
</NavLink>
<Grid container style={{paddingTop:'2rem',textAlign:'center'}}>
<Grid item xs={2}></Grid>
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<Select
defaultValue={1}
labelId="sharpeYear1"
id="sharpeYear1-select"
value={values.sharpeYear1}
label="Year"
onChange={handleChange("sharpeYear1")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio1Cutoff}
onChange={ handleChange("sharperatio1Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid >
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<Select
defaultValue={5}
labelId="sharpeYear2"
id="sharpeYear2-select"
value={values.sharpeYear2}
label="Year"
onChange={handleChange("sharpeYear2")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio2Cutoff}
onChange={handleChange("sharperatio2Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid>
</Grid>
<div style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
{isPending&&<div>Loading Data...</div>}
{error &&<div>"This is awkard..."{error}</div>}
{!isPending && stockPerformance&&
<div style={{height:500,width:'70%'}}>
<DataGrid
rows={stockPerformance}
columns={columns}
></DataGrid>
</div>
}
</div>
</div>
)
}
React useState is asynchronous, so updating state & then accessing it immediately in next line will not work. Updated state is only available on the next render cycle.
The below will not console log the updated state. Same for setUrl.
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values) // state is not yet updated
If you want to perform an action on state update, you need to use the useEffect hook, much like using componentDidUpdate in class components since the setter returned by useState doesn't have a callback pattern
useEffect(() => {
// action on update of values
console.log(values) // updated state is available here
}, [values]);
You can clone the values state, make your changes by mutating and update your state. Then use the modified object to calculate the url so it has the new values.
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
seturl(
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
newValues.sharpeYear1 +
'&LongYearNum=' +
newValues.sharpeYear2 +
'&sharpeRatio1=' +
newValues.sharperatio1Cutoff +
'&sharpeRatio2=' +
newValues.sharperatio2Cutoff
);
};
Or even better, calculate url in a second time (not directly in your handler), plus it doesn't have to be in the state.
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
};
const url = useMemo(() => {
return (
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
values.sharpeYear1 +
'&LongYearNum=' +
values.sharpeYear2 +
'&sharpeRatio1=' +
values.sharperatio1Cutoff +
'&sharpeRatio2=' +
values.sharperatio2Cutoff
);
}, [values]);
By the way, event could be null in this callback, destructure it so it's assigned to a variable or use event.persist().
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
This works but the when i console log the object it gives
{ "week":undefined, "name":undefined, "code":undefined }
Moreover does wrapping all the material ui component in form tag and treating the whole code as a form, is it appropriate?
here is my code:
const ExamSimulatorForm = () => {
const weekNumber = useRef();
const examSub = useRef();
const examCode = useRef();
const handleSubmit = (event) =>{
event.preventDefault()
const week = weekNumber.current.value
const subject = examSub.current.value
const code = examCode.current.value
const examSimulatorPayload = {
week:week,
subject:subject,
code:code
}
console.log(examSimulatorPayload)
}
const [code, setCode] = useState('Quiz');
const [examSubject, setExamSubject] = useState('');
const [field, setField] = useState(1)
const handleESubjectChange = (event) => {
setExamSubject(event.target.value);
};
const handleCode = (event) => {
setCode(event.target.value);
};
return (
<form >
<CardActions onSubmit={handleSubmit}>
<Grid container spacing={2} justifyContent='center' alignItems='center' direction='column'>
<Grid item>
<TextField
InputProps={{
inputProps: {
max: 12, min: 1
}
}}
label='Week'
type='number'
onChange={(event)=>setField(parseInt(event.target.value))}
style={{minWidth:250}}
ref = {weekNumber}
required
/>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel>Subject</InputLabel>
<Select
value={examSubject}
onChange={handleESubjectChange}
ref={examSub}
required
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel id="exam-code" >Exam Code</InputLabel>
<Select
labelId="exam-code"
id="exam-code-select"
value={code}
onChange={handleCode}
ref={examCode}
required
>
<MenuItem value={'Q'}>Q</MenuItem>
<MenuItem value={'M'}>M</MenuItem>
<MenuItem value={'F'}>F</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<Button variant='contained' color='primary' style={{marginTop:94}} >Take Exam</Button>
</Grid>
</Grid>
</CardActions>
</form>
)
}
export default ExamSimulatorForm;
I have a similar form for attendance simulation, attendance dataset generation and exam dataset generation
I think this is good for you.
Please try this.
const ExamSimulatorForm = () => {
const [state, setState] = useState({
code: 'Quiz',
subject: '',
week: 1
});
const handleSubmit = (event) =>{
event.preventDefault()
const examSimulatorPayload = state;
console.log(examSimulatorPayload)
}
const handleChange = (evt, name) {
const { value } = evt.target;
setState({
...state,
[name]: value
});
}
return (
<form onSubmit={handleSubmit}>
<CardActions>
<Grid container spacing={2} justifyContent='center'
alignItems='center' direction='column'>
<Grid item>
<TextField
InputProps={{
inputProps: {
max: 12, min: 1
}
}}
label='Week'
type='number'
value={state.week}
onChange={(event)=>handleChange( event, "week")}
style={{minWidth:250}}
required
/>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel>Subject</InputLabel>
<Select
value={state.subject}
onChange={(event)=>handleChange( event, "subject")}
required
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel id="exam-code" >Exam Code</InputLabel>
<Select
labelId="exam-code"
id="exam-code-select"
value={state.code}
onChange={(event)=>handleChange( event, "code")}
required
>
<MenuItem value={'Q'}>Q</MenuItem>
<MenuItem value={'M'}>M</MenuItem>
<MenuItem value={'F'}>F</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<Button variant='contained' color='primary' style=
{{marginTop:94}} >Take Exam</Button>
</Grid>
</Grid>
</CardActions>
</form>
)
}
export default ExamSimulatorForm;
Please check it above code, and let me know your idea.
State updates in react are asynchronus, which means they don't occur as soon as you call them. You have to wait until the state updates to console.log because otherwise, nothing has changed and you are getting the initial value. You could do something like this:
useEffect(() => {
const subject = examSub.current.value
console.log(subject)
}, [examSubject])
useEffect() executes an action every time a state changes. Notice how at the end there is an array, with [examSubject]. This signifies the state that will trigger the effect. So when examSubject changes (when you assign a value to it), the effect will execute (in this case, it will log the subject).
When writing code, at least in my case, you don't need to worry about this. You can chnage the state and write your code as normal, but react might take a second or two to update the state. The only time I really notice this is when I console.log.
You can define the state for your inputs :
const [code, setCode] = React.useState('');
const [subject, setSubject] = React.useState('');
const [week, setWeek] = React.useState('');
const setExamCode = event => {
setCode(event.target.value);
};
const setSubject = event => {
setSubject(event.target.value);
};
const setWeek = event => {
setWeek(event.target.value);
};
Then call these methods from onChange event like : onChange={setExamCode} or {setSubject}
In case you want to handle data from single event and defining it's initial state try below approach :
const initialData = Object.freeze({
code: "",
subject: "",
week: ""
});
const [data, updateData] = React.useState(initialData );
const handleChange = (e) => {
updateData({
...data,
[e.target.name]: e.target.value
});
};
const handleSubmit = (e) => {
e.preventDefault()
console.log(data);
};
Then call these methods from onChange event like onChange={handleSubmit}
I have a registration page created in ReactJS. One of the fields is a checkbox isadult. When I click on Register button and save the fields in a database (MongoDB), the value of isadult appears as [Object object] instead of a concrete value: True or False.
What am I doing wrong?
import React from 'react';
import { Paper, makeStyles, Grid, TextField, Button, Switch } from '#material-ui/core';
import config from '../../config/config.json';
import axios from 'axios';
const useStyles = makeStyles((theme) => ({
root: {
minWidth: '300px',
width: '50%',
padding: '20px 20px 20px 20px',
margin: 'auto'
}
}));
const Register = () => {
const classes = useStyles();
const [username, setUsername] = React.useState('');
const [password, setPassword] = React.useState('');
const [isadult, setIsAdult] = React.useState('');
const handleChangeIsAdult = (event) => {
setIsAdult({
...isadult,
[event.target.name]: event.target.value,
});
}
const handleRegister = () => {
if (username && password) {
const formData = new FormData();
formData.append('username', username);
formData.append('password', password);
formData.append('isadult', isadult);
axios.post(config.api.url + '/auth/register', formData)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
}
return (
<Paper className={classes.root}>
<div >
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<TextField
id="username"
label="Username"
type="email"
fullWidth
value={username}
onChange={(e) => setUsername(e.target.value)}
autoFocus />
</Grid>
</Grid>
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<TextField
id="password"
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
fullWidth />
</Grid>
</Grid>
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<label>Is adult?</label>
<input
type='checkbox'
onChange={(event) => {
handleChangeIsAdult({
target: {
name: event.target.name,
value: event.target.checked,
},
});
}}
/>
</Grid>
</Grid>
<Grid container justify="center" style={{ marginTop: '10px' }}>
<Button
variant="outlined"
color="primary"
style={{ textTransform: "none" }}
onClick={handleRegister}
>
Register
</Button>
</Grid>
</div>
</Paper>
);
}
export default Register;
As your isadult state property is intended for use in the checkbox input, it needs to be declared and updated as a boolean.
You are declaring the propery as follows:
const [isadult, setIsAdult] = React.useState('');
The initial assignment is the empty string (''), which may cause issues with other places in your application code if they expect that property to be of type boolean. What you should do instead is start it off as a boolean:
const [isadult, setIsAdult] = React.useState(false);
Now, the main problem you are facing is the fact that the form data is being serialized with isadult being an object. This problem is coming from the fact that you are assigning an object to it through setIsAdult:
setIsAdult({
...isadult,
[event.target.name]: event.target.value,
});
The state property setter appends whatever value is passed to it directly to the property it is attached to. It works differently from setState that expects a state object. The right way to use the method in this case is:
setIsAdult(event.target.value);
Here, event.target.value contains exactly the checkbox checked boolean value that should go into isadult. Now, this property is serialized correctly as a boolean in your formData.
I had a form that has a lot of lag due to a large amount of state being handled for user's with a large number of job posts etc. I am trying to subdue this lag my switching my onChange to onBlur, this works great. The only problem is that my form no longer gets set to InitialState( empty string). I also have a submit button that I am keeping invalid until all inputs are filled. due to the onblur it remains invalid until I click away from the form. Is there a way I can still reset a form when using onBlur?? and does anyone have a solution to the issue of my button remaining invalid until I click away from the form. My inputs code are as follows:
the handleSubmit function:
const handleSubmit = async e => {
e.preventDefault()
setIsLoading(true)
const fireToken = await localStorage.FBIdToken
await axios
.post(`/job`, formData, {
headers: {
Authorization: `${fireToken}`
}
})
.then(res => {
setOpen(true)
setMessage(res.data)
fetchUser()
setIsLoading(false)
setIsModalOpen(false)
setFormData(INITIAL_STATE)
})
.catch(err => {
setErrors(err.response.data)
console.log(err)
setIsLoading(false)
})
}
The form code:
import React from 'react'
// components
import SelectStatus from './SelectStatus'
// Material UI Stuff
import CircularProgress from '#material-ui/core/CircularProgress'
import Typography from '#material-ui/core/Typography'
import TextField from '#material-ui/core/TextField'
import CardContent from '#material-ui/core/CardContent'
import Button from '#material-ui/core/Button'
import Card from '#material-ui/core/Card'
import Grid from '#material-ui/core/Grid'
// JobCardStyles
import useJobCardStyles from '../styles/JobCardStyles'
const NewJobForm = React.forwardRef(
({ handleSubmit, formData, handleInputChange, isloading }, ref) => {
const { company, position, status, link } = formData
const isInvalid = !company || !position || !link || !status || isloading
const classes = useJobCardStyles()
return (
<Card className={classes.card}>
<CardContent className={classes.content}>
<form noValidate onSubmit={handleSubmit} className={classes.form}>
<Grid
container
spacing={2}
alignItems="center"
justify="space-between"
>
<Grid item sm="auto" xs={12} className={classes.grid}>
<Typography>New</Typography>
<Typography>Job</Typography>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="company"
type="company"
label="Company"
name="company"
autoComplete="company"
defaultValue={company}
onBlur={handleInputChange('company')}
/>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="position"
type="position"
label="Position"
name="position"
autoComplete="position"
defaultValue={position}
onBlur={handleInputChange('position')}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<SelectStatus
status={status}
handleInputChange={handleInputChange}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="link"
type="text"
label="Link"
name="link"
autoComplete="link"
defaultValue={link}
onBlur={handleInputChange('link')}
/>
</Grid>
<Grid item sm={1} xs={12} className={classes.grid}>
<Button
fullWidth
type="submit"
variant="contained"
color="primary"
disabled={isInvalid}
className={classes.submit}
disableElevation
>
Submit
{isloading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
)
export default NewJobForm
Try making another function to wrap several functions.
const NewJobForm = React.forwardRef(
//other logic
const reset = () => {//your reset function logic}
//ver 1
const handleOnBlur = (fn, relatedParam) => {
reset();
fn(relatedParam);
}
//ver 2
const handleOnBlur = (relatedParam) => {
reset();
handleInputChange(relatedParam);
}
return (
<TextField
//other props
onBlur={() => handleOnBlur('company')}
/>
)