How to use React hook in a react class? - javascript

As a newbie in JS world i am in a big trouble ...
I am using a react hook
import { useKeycloak } from '#react-keycloak/web';
import { useCallback } from 'react';
export const useAuthenticatedCallback = (callbackFn) => {
const [keycloak, initialized] = useKeycloak()
const authCallback = useCallback(() => {
// Do nothing while Keycloak is initializing
if (!initialized) {
return
}
// if user is not authenticated redirect to login
if (!keycloak.authenticated) {
return keycloak.login()
}
// otherwise invoke function
return callbackFn()
}, [callbackFn, initialized, keycloak])
return authCallback
}
and able to use inside a function
import React from "react";
import {Grid, Avatar, Chip } from '#material-ui/core';
import { useAuthenticatedCallback } from '../../shared/keycloak/KeycloakOnDemand'
// Tranding function component
function Tranding(props) {
const yourCallback = () => {
// The code you need to be authenticated to run
return yourCallback;
};
const authenticatedCallback = useAuthenticatedCallback(yourCallback);
return (
<Grid container spacing={3}>
<Grid className="text-center" item sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>
</div>
</Grid>
</Grid>
);
}
// export the component.
export default Tranding;
Upto here everything fine and things are working according to requirement.
Now i got a challenge to use same hook inside a react component class ,but fail to achieve this ..Can anyone help for this issue?
I was trying to use in this class
import React from "react";
import {connect} from 'react-redux';
import PostList from "./PostList";
import Grid from '#material-ui/core/Grid';
import Switch from '#material-ui/core/Switch';
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import Autocomplete from '#material-ui/lab/Autocomplete';
import { TextField, ButtonGroup, Button } from '#material-ui/core';
import SaveIcon from '#material-ui/icons/Save';
import TextEditor from './TextEditor';
//import CKTextEditor from '../../shared/CKTextEditor';
import {NotificationContainer, NotificationManager} from 'react-notifications';
import CircularSpinner from '../../shared/CircularSpinner';
import postService from '../../services/PostService';
class Posts extends React.Component {
constructor() {
super()
this.state = {
posts: [],
totalPages: 0,
isLoading: false,
postForm: {
isValidationActive: false,
tradeTypeId: 1,
tradeTypeText: 'Buy',
price: '', priceValid: false,
stopLoss: '', stopLossValid: false,
targetPrice: '', targetPriceValid: false,
targetDate: '', targetDateValid: false,
title: '',
notes: '', notesValid: false
},
analysisForm: {
isValidationActive: false,
title: '', titleValid: false,
notes: '', notesTemp:'', notesValid: false
},
isTradeCallActive: true,
tradeCallFormValid: false,
analysisFormValid: false,
companyCode: '',
companyValid: false,
postTypes: [],
tradeCallTypes: [],
companies: [],
tradeTypeSelected: 'Buy'
};
this.formRef = null;
this.handleChange = this.handleChange.bind(this);
this.onCompanyCodeChange = this.onCompanyCodeChange.bind(this);
this.handleEditorChange = this.handleEditorChange.bind(this);
this.handleTradeCallSubmit = this.handleTradeCallSubmit.bind(this);
this.handleAnalysisSubmit = this.handleAnalysisSubmit.bind(this);
this.loadFormModel = this.loadFormModel.bind(this);
this.clearTradeCallForm = this.clearTradeCallForm.bind(this);
this.clearAnalysisForm = this.clearAnalysisForm.bind(this);
this.loadPosts = this.loadPosts.bind(this);
}
// handle chnage events for all controls.
handleChange(event) {
let _postForm = this.state.postForm;
let _isTradeCallActive = this.state.isTradeCallActive;
let _targetValue = event.target.value;
let _companyValid = this.state.companyValid;
let _companyCode = this.state.companyCode;
if(event.target.name === 'TradeCall' || event.target.name === 'Analysis'){
if(event.target.name === 'Analysis' && event.target.checked) {_isTradeCallActive = false;}
if(event.target.name === 'TradeCall' && event.target.checked) {_isTradeCallActive = true;}
}
if(event.target.name === 'txtCompany') {
_companyCode = _targetValue;
if (_targetValue.length < 3) { _companyValid = false; }
}
if(event.target.name === 'txtTitle'){
let _analysisForm = this.state.analysisForm;
_analysisForm.titleValid = true;
_analysisForm.title = _targetValue;
if (_targetValue.length < 10) { _analysisForm.titleValid = false; }
let _analysisFormValid = false;
if(_analysisForm.titleValid && _analysisForm.notesValid) {
_analysisFormValid = true;
}
this.setState({ ...this.state, analysisForm: _analysisForm, analysisFormValid: _analysisFormValid});
return;
}
if(event.target.name === 'txtPrice'
|| event.target.name === 'txtStoploss'
|| event.target.name === 'txtTarget'
|| event.target.name === 'notesTextArea'
|| event.target.name === 'targetDate'
|| event.target.name === 'selectTradeType'){
if(event.target.name === 'txtPrice') {
_postForm.priceValid = true;
_postForm.price = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.priceValid = false; }
}
if(event.target.name === 'txtStoploss') {
_postForm.stopLossValid = true;
_postForm.stopLoss = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.stopLossValid = false; }
}
if(event.target.name === 'txtTarget') {
_postForm.targetPriceValid = true;
_postForm.targetPrice = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.targetPriceValid = false; }
}
if(event.target.name === 'notesTextArea') {
_postForm.notesValid = true;
_postForm.notes = _targetValue;
if (_targetValue.length < 20) { _postForm.notesValid = false; }
}
if(event.target.name === 'targetDate') {
_postForm.targetDateValid = true;
_postForm.targetDate = _targetValue;
if (_targetValue.length < 8) { _postForm.targetDateValid = false; }
}
}
let _tradeType = this.state.tradeCallTypes.find(x => x.Name === this.state.tradeTypeSelected)
_postForm.tradeTypeId = _tradeType.Id;
_postForm.tradeTypeText = _tradeType.Name;
let _tradeCallFormValid = false;
if(this.state.companyValid && _postForm.priceValid && _postForm.stopLossValid && _postForm.targetPriceValid && _postForm.targetDateValid && _postForm.notesValid) {
_tradeCallFormValid = true;
_postForm.title = `${_postForm.tradeTypeText} ${this.state.companyCode} at price ${_postForm.price} for target ${_postForm.targetPrice} by date ${_postForm.targetDate} with SL ${_postForm.stopLoss}`;
}
this.setState({ ...this.state, postForm: _postForm, tradeCallFormValid: _tradeCallFormValid, isTradeCallActive: _isTradeCallActive, companyValid: _companyValid, companyCode: _companyCode });
};
// handle trade call submit click.
handleTradeCallSubmit(){
if(this.state.tradeCallFormValid){
// To DO
this.setState({ ...this.state, tradeCallFormValid: false});
let _postForm = this.state.postForm;
let _companyCode = this.state.companyCode;
let requestBody = {
eventType:'create-trade-call-post',
callType:_postForm.tradeTypeId,
symbol:_companyCode,
userId: this.props.activeUser.Id,
price:_postForm.price,
stopLoss:_postForm.stopLoss,
targetPrice:_postForm.targetPrice,
targetDate:_postForm.targetDate,
tags: _companyCode,
title:_postForm.title,
notes:_postForm.notes
}
postService.create(requestBody)
.then((result) => {
NotificationManager.success(`Trade call post created successfully...`);
this.loadPosts(1);
this.clearTradeCallForm();
}).catch((error) => {
NotificationManager.error(`Trade call post creation failed..`);
console.log(`Error: ${error}`);
});
} else {
let _postForm = this.state.postForm;
_postForm.isValidationActive = true;
this.setState({ ...this.state, postForm: _postForm});
}
}
// component did mount event called after the virtual DOM loaded.
componentDidMount() {
this.setState({ ...this.state, isLoading: true });
this.loadFormModel();
}
render() {
if (this.state.isLoading) {
return <CircularSpinner />;
}
return (
<div>
<NotificationContainer/>
<Card>
<CardContent>
<form ref={(ref) => this.formRef = ref} noValidate autoComplete="off">
<Grid className="text-center" container spacing={2}>
{
this.state.postTypes.map((postType, index) =>
<Grid key={postType.Id} item sm={6} xs={6} md={3}>
<h5>{postType.Name} <Switch key={postType.Id} checked={(postType.Name === 'TradeCall')?this.state.isTradeCallActive: !this.state.isTradeCallActive} value={postType.Id} onChange={this.handleChange} name={postType.Name} inputProps={(postType.Name === 'TradeCall') ? {'aria-label': 'secondary checkbox' }: { 'aria-label': 'primary checkbox' }} /></h5>
</Grid>
)
}
<Grid item sm={12} xs={12} md={6}>
<Autocomplete
id="companyAutocomplete"
options={this.state.companies}
getOptionLabel={(option) => option.Symbol}
onInputChange={this.onCompanyCodeChange}
fullWidth
renderInput={(params) => <TextField fullWidth id="txtCompany" {...params}
error={((this.state.postForm.isValidationActive || this.state.analysisForm.isValidationActive))
&& !this.state.companyValid} name="txtCompany" size="small" label="Company" onChange={this.handleChange} variant="outlined" placeholder="Company.." />}
/>
</Grid>
</Grid>
<div className={!this.state.isTradeCallActive ? 'hidden' : ''}>
<Grid container spacing={2}>
<Grid item sm={12} xs={12} md={2}>
<ButtonGroup fullWidth aria-label="small button group">
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Sale"})}}
variant={(this.state.tradeTypeSelected === "Buy") ? "outlined" : "contained"}
color={(this.state.tradeTypeSelected === "Buy") ? "default" : "secondary"}> Sale
</Button>
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Buy"})}}
variant={(this.state.tradeTypeSelected === "Buy") ? "contained" : "outlined"}
color={(this.state.tradeTypeSelected === "Buy") ? "secondary" : "default"}> Buy
</Button>
</ButtonGroup>
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtPrice" error={this.state.postForm.isValidationActive && !this.state.postForm.priceValid} name="txtPrice" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Price" onChange={this.handleChange} variant="outlined" placeholder="Price.." />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtStoploss" error={this.state.postForm.isValidationActive && !this.state.postForm.stopLossValid} name="txtStoploss" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Stoploss" onChange={this.handleChange} variant="outlined" placeholder="SL.." />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtTarget" error={this.state.postForm.isValidationActive && !this.state.postForm.targetPriceValid} name="txtTarget" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Target price" onChange={this.handleChange} variant="outlined" placeholder="Price.." />
</Grid>
<Grid item sm={12} xs={12} md={4}>
<TextField fullWidth id="targetDate" error={this.state.postForm.isValidationActive && !this.state.postForm.targetDateValid} name="targetDate" onChange={this.handleChange} type="date" size="small" label="Target date" variant="outlined" InputLabelProps={{ shrink: true, }} />
</Grid>
</Grid>
<Grid container spacing={2}>
<Grid item sm={12} xs={12} md={12}>
<TextField id="notesTextArea" error={this.state.postForm.isValidationActive && !this.state.postForm.notesValid} name="notesTextArea" onChange={this.handleChange} size="medium" fullWidth
placeholder="Enter notes here.." variant="outlined" label="Notes"
multiline rows={3} rowsMax={4} />
</Grid>
</Grid>
<Grid justify="center" container spacing={2}>
<Grid item sm={12} xs={12} md={3}>
<Button size="medium" fullWidth id="btnSubmit" startIcon={<SaveIcon />} onClick={this.handleTradeCallSubmit} variant="contained" color="primary"> Save </Button>
</Grid>
</Grid>
</div>
</form>
</CardContent>
</Card>
<Grid container spacing={3}>
<Grid item md={12}>
<PostList totalPages={this.state.totalPages} posts={this.state.posts} loadPosts={this.loadPosts} />
</Grid>
</Grid>
</div>
)
}
}
// Map redux state to props
const mapStateToProps = state => ({
activeUser: state.session.activeUser
});
// export the component.
export default connect(mapStateToProps)(Posts);
So before calling handleTradeCallSubmit() method i want to check user is login or not if not login redirect to login page otherwise process the method?

You can not use a Hook inside a react Class.
Hooks are functions that let you “hook into” React state and lifecycle
features from function components. Hooks don’t work inside classes —
they let you use React without classes. (We don’t recommend rewriting
your existing components overnight but you can start using Hooks in
the new ones if you’d like.)
https://reactjs.org/docs/hooks-overview.html#:~:text=Hooks%20are%20functions%20that%20let,if%20you'd%20like.)

Although use hooks cannot be used inside a class component, hook components can be used inside a class component.
So one solution is to create a component that uses the hook, and then use the component inside the class instead.
function AuthenticatedCallback(props) {
const authenticatedCallback = useAuthenticatedCallback(props.callbackFn);
return props.children(authenticatedCallback);
}
//from inside the class component.
......
return (
<AuthenticatedCallback>{authenticatedCallback =>
<Grid container spacing={3}>
<Grid className="text-center" item sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>
</div>
</Grid>
</Grid>}
</AuthenticatedCallback>
);
Notice how I'm using the props.children as a functional callback to pass this down to the component.

Related

How to send/receive props to BasicLayout (#devexpress/dx-react-scheduler)

I'm from Angular and new to React. Im doing well but here is a problem I'm stuck at. As you can see I have BasicLayout and AppointmentForm, both are in one file. BasicLayout is being used inside AppointmentForm but not like an element i.e <BasicLayout/> so I'm not able to understand how to pass props or its even possible now. I want to trigger commitChanges(inside AppointmentForm) function when onSubmit(inside Basic Layout) function is triggered. How can I pass props between these components?
const BasicLayout = (props) => {
const formik = useFormik({
initialValues: {
title: '',
agenda: '',
description: '',
participants: [],
host: user?.id,
guest: '',
location: '',
},
validationSchema,
onSubmit: async (values) => {
values.startDate = props.appointmentData.startDate;
values.endDate = props.appointmentData.endDate;
values.guest = values.guest?._id;
createAppointment(values);
console.log(values);
},
});
return (
<Container>
<Typography sx={{ fontSize: 24, fontWeight: 'bold' }} color="text.primary" gutterBottom>
Create Appointment
</Typography>
<Box sx={{ flexGrow: 1 }}>
<FormikProvider value={formik}>
<Form autoComplete="off" onSubmit={handleSubmit}>
<Grid container spacing={2}>
<Grid item xs={6} md={6}>
<TextField
label="Title"
color="secondary"
id="title"
type="text"
key="title"
value={formik.values.title}
onChange={formik.handleChange}
{...getFieldProps('title')}
error={Boolean(touched.title && errors.title)}
helperText={touched.title && errors.title}
fullWidth
/>
</Grid>
<Grid item container xs={12} md={12} direction="row" justifyContent="center" alignItems="center">
<LoadingButton size="medium" type="submit" variant="contained" loading={isSubmitting}>
Create
</LoadingButton>
</Grid>
</Grid>
</Form>
</FormikProvider>
</Box>
<ToastContainer />
</Container>
);
};
const AppointmentsDashboard = (props) => {
const commitChanges = ({ added, changed, deleted }) => {
console.log(props);
console.log({ added, changed, deleted });
if (added) {
if (!isValidate) {
notify('Please fill all required fields', 'error');
return;
}
const startingAddedId = data.length > 0 ? data[data.length - 1].id + 1 : 0;
setData([...data, { id: startingAddedId, ...added }]);
}
if (changed) {
setData(
data.map((appointment) =>
changed[appointment.id] ? { ...appointment, ...changed[appointment.id] } : appointment
)
);
}
if (deleted !== undefined) {
setData(data.filter((appointment) => appointment.id !== deleted));
}
return data;
};
return (
<>
<Paper>
<Scheduler data={data} height={660}>
<ViewState currentDate={currentDate} />
<EditingState
onCommitChanges={commitChanges}
addedAppointment={addedAppointment}
onAddedAppointmentChange={changeAddedAppointment}
appointmentChanges={appointmentChanges}
onAppointmentChangesChange={changeAppointmentChanges}
editingAppointment={editingAppointment}
onEditingAppointmentChange={changeEditingAppointment}
onAppointmentFormClosing={() => {
console.log('asdasd');
}}
allowAdding={true}
/>
<WeekView startDayHour={9} endDayHour={17} />
<AllDayPanel />
<EditRecurrenceMenu />
<ConfirmationDialog />
<Appointments />
<AppointmentTooltip showOpenButton showDeleteButton />
<AppointmentForm basicLayoutComponent={BasicLayout} />
</Scheduler>
</Paper>
</>
);
};
export default AppointmentsDashboard;

How can I update the values of Object.entries?

export const data = [
{
size: "S",
colorMap: { Yellow: 10, Green: 5, Black: 50 },
productName: "Shirt",
price: 200
}
];
I wanted to show the initial values of the colorMapand then update its quantity. How can I update the quantities of the colors which are the values of the Object.entries(colorMap)?
Codesandbox: https://codesandbox.io/s/form-changehanlder-2-2repsp?file=/part2.js
The product here came from the parent component:
This is the child component
import React, { useState } from "react";
import { Grid, TextField } from "#mui/material";
const Part2 = ({ product }) => {
const [qty, setQty] = useState();
const handleSubmit = (e) => {
e.preventDefault();
console.log(qty);
};
return (
<div>
{product &&
product.map((prod, index) => (
<>
<Grid item key={index}>
<form onSubmit={handleSubmit}>
{Object.entries(prod.colorMap).map((color, index) => (
<Grid
container
rowSpacing={1}
columnSpacing={{ xs: 1, sm: 2, md: 3 }}
key={color[0]}
>
<Grid item xs={6}>
<TextField
type="text"
variant="outlined"
label="Color"
fullWidth
value={color[0]}
disabled
/>
</Grid>
<Grid item xs={6}>
<TextField
type="number"
variant="outlined"
fullWidth
label="Quantity"
value={color[1]}
onChange={(e) => console.log(index)}
/>
</Grid>
</Grid>
))}
</form>
</Grid>
</>
))}
</div>
);
};
export default Part2;
First make changeHandler in demo.js as you are using React State in demo.js so you have to make onChangeHandler in that file and pass it in props of part2.
Like:
const onChangeValues = (propertyName, index, value) => {
let item = product?.[index];
if (item) {
item.colorMap[propertyName] = value;
let prods = [...product];
prods[index] = item;
setProduct(prods);
}
};
And pass this function in props of Part2:
<Grid item>
<Part2 product={product} onChange={onChangeValues} />
</Grid>
In part2 Component you can consume it as follows:
<TextField
type="number"
variant="outlined"
fullWidth
label="Quantity"
value={color[1]}
onChange={({ target: { value } }) => {
onChangeHandler(color[0], index, value);
}}
/>
Codesandbox Link: https://codesandbox.io/s/form-changehanlder-2-forked-l9unl0?file=/part2.js:1131-1521

how to show error note for only when a particular object value is empty in text field in reactjs

My Objective is to show error to the particular object id when we dont enter any value in the textfield in onChange method. But it is appearing in the other id text field.
JSON data looks in this way:
"details": [
{ "id": "12wer1", "name": "ABC", "age": 15 },
{ "id": "78hbg5", "name": "FRE", "age": 21 }
]
I've tried in this way:
{this.state.details.map((y) => (
<Grid container justify="center" spacing={2}>
<Grid item xs={3}>
<TextField label="Name" name="dName" variant="outlined" value={y.name}
onChange={(e)=>this.onChange(e.target.name, e.target.value)}
/>
</Grid>
<Grid item xs={3}>
<TextField label="Age" name="age"variant="outlined" value={y.age} onChange={(e)=>this.onChange(e.target.name, e.target.value)}/>
<FormHelperText >
{this.state.errors.age}
</FormHelperText>
</Grid>
</Grid>
))}
OnChange method:
onChange = (name, value)=> {
this.state.details.forEach((item) => {
if (!item.age) {
errors.age = "age is required";
}
else {
errors.age = ""
}
}
I'm getting error in other ids also. for example i want to clear the age for 1st id then error is showing on both the ids.
Can anyone help me to fix this error?
We will have to something like this.
import React from "react";
import { Grid, TextField, FormHelperText } from "#material-ui/core";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
details: [
{ id: "12wer1", name: "ABC", age: 15 },
{ id: "78hbg5", name: "FRE", age: 21 }
],
errors: {
name: {},
age: {}
}
};
this.onNameChange = this.onChange.bind(this, "name");
this.onAgeChange = this.onChange.bind(this, "age");
}
onChange = (property, id, e) => {
const value = e.target.value;
let { details, errors } = this.state;
details.forEach((d) => {
if (d.id === id) {
d[property] = value;
errors[property][id] = value === "" ? `${property} is required` : "";
}
});
console.log(errors);
this.setState({
details: details,
errors: errors
});
};
render() {
return (
<div className="App">
{this.state.details.map((y) => (
<Grid container justify="center" spacing={2}>
<Grid item xs={3}>
<TextField
label="Name"
name="dName"
variant="outlined"
value={y.name}
onChange={(e) => this.onNameChange(y.id, e)}
/>
<FormHelperText>
{this.state.errors.name[y.id] || ""}
</FormHelperText>
</Grid>
<Grid item xs={3}>
<TextField
label="Age"
name="age"
variant="outlined"
value={y.age}
onChange={(e) => this.onAgeChange(y.id, e)}
/>
<FormHelperText>
{this.state.errors.age[y.id] || ""}
</FormHelperText>
</Grid>
</Grid>
))}
</div>
);
}
}
We basically have to link each error's object with it's specific rendered element.
Here is the running code for the same: codesandbox

Resetting a form when using onBlur as opposed to onChange

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')}
/>
)

Unable to get the input from a textfield in React

I'm trying to get the input from a text-field in react but it just doesn't work and I have no clue why. I have looked at a lot of different solutions but none of them seem to work.
I even tried to follow this https://reactjs.org/docs/refs-and-the-dom.html but I'm not understanding this correctly?
class Activity extends Component {
constructor(props) {
super(props);
this.newActivity = React.createRef();
}
callAPI() {
fetch("http://localhost:5000/activities", {
method: 'POST',
body: JSON.stringify({
newName: this.newActivity.current,
oldName: this.state.activity
}),
})
.then(function (response) {
return response.json()
});
}
state = {
activity: this.props.data.name
}
render() {
return (
<React.Fragment>
<Grid justify="center" container spacing={(2, 10)} aligncontent="center">
<Grid item xs={8} >
<Paper>
{/*Trying to get the input here so that I can put it into my POST request*/}
<TextField inputRef={el => this.newActivity = el} type="activity" id="standard-basic" label="Standard" defaultValue={this.state.activity} />
</Paper>
</Grid>
<Grid item xs={2}>
<Button onClick={this.callAPI} variant="contained" startIcon={<UpdateIcon />} style={buttonStyle} >Uppdatera</Button>
</Grid>
<Grid item xs={2}>
<Button variant="contained" startIcon={<DeleteIcon />} style={buttonStyle} >Ta Bort</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
The error I get is
TypeError: Cannot read property 'newActivity' of undefined
You must initiate state values inside the constructor.
Also change this line as inputRef={this.newActivity} instead of inputRef={(el)=>this.newActivity =el}. Because you already create ref using createRef no need to create again.
class Activity extends Component {
constructor(props) {
super(props);
this.state = {
activity: this.props.data.name
}
this.callAPI = this.callAPI.bind(this);
this.newActivity = React.createRef();
}
callAPI() {
fetch("http://localhost:5000/activities", {
method: 'POST',
body: JSON.stringify({
newName: this.newActivity.current,
oldName: this.state.activity
}),
})
.then(function (response) {
return response.json()
});
}
render() {
return (
<React.Fragment>
<Grid justify="center" container spacing={(2, 10)} aligncontent="center">
<Grid item xs={8} >
<Paper>
{/*Trying to get the input here so that I can put it into my POST request*/}
<TextField inputRef={this.newActivity} type="activity" id="standard-basic" label="Standard" defaultValue={this.state.activity} />
</Paper>
</Grid>
<Grid item xs={2}>
<Button onClick={this.callAPI} variant="contained" startIcon={<UpdateIcon />} style={buttonStyle} >Uppdatera</Button>
</Grid>
<Grid item xs={2}>
<Button variant="contained" startIcon={<DeleteIcon />} style={buttonStyle} >Ta Bort</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
TextField is a wrapper component.
You can pass the ref to the native input like this:
import React, { Component, createRef } from 'react';
import TextField from '#material-ui/core/TextField';
export default class App extends Component {
ref = createRef();
render() {
return (
<div className="App">
<TextField inputProps={{ ref: this.ref }} />
</div>
);
}
}

Categories

Resources