Unable to update form field in react via prevState - reactjs

I have a state variable as:
constructor(props) {
super(props)
this.state = {
fields: {
applicantName: '',
applicantType: '',
applicantAddress: '',
applicantContact: '',
buildingName: '',
buildingAddress: '',
area:'',
}
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
and I have a function :
handleChange(event) {
this.setState((prevState) => {
fields: {
...prevState.fields, //Unexpected token ..
{
event.target.name: event.target.value,
},
}
});
}
How I am not able to see any type of syntax here...but my module build fails and it says syntax error near '...'

you need return Object
handleChange(event) {
// note here => ({
this.setState((prevSate) => ({
fields: {
...prevState.fields,
//and there ..
[event.target.name]: event.target.value
})
});
}
UPDATE
Based on Abdullah suggestion, its better when you use ...prevState for wohle state:
handleChange(event) {
// note here => ({
this.setState((prevSate) => ({
// note change here
...prevState,
fields: {
...prevState.fields,
//and there ..
[event.target.name]: event.target.value
})
});
}
UPDATE 2
based on PraveenRaoChavan comment:
typo fix:
need use event not e

handleChange(event) {
this.setState(prevState => ({
fields: {
...prevState.fields,
{
event.target.name: e.target.value,
},
}
}));
}

You have a typo in there
change
this.setState((prevSate) => { }
to
this.setState((prevState) => { }

Related

How do I clear/delete a grocery item in React?

How do I clear/delete a grocery item? I need to make a button that clears a grocery item after I click it. TIA
Here's the code this is for a HW assignment:
class App extends Component {
state = {
grocery: grocery,
item: '',
brand: '',
units: Number,
quantity: Number,
isPurchased: Boolean
}
handleChange = (e) => {
this.setState({ [e.target.id]: e.target.value })
}
handleSubmit = (e) => {
e.preventDefault()
const addGrocery = {
item: this.state.item,
brand: this.state.brand,
units: this.state.units,
quantity: this.state.quantity,
}
this.setState({
grocery: [addGrocery, ...this.state.grocery],
item: '',
brand: '',
units: Number,
quantity: Number,
})
const removeGrocery = {
item: this.state.item
}
}
Here is some codes bro. I fixed something that will give you error in future.
const initialValue = {
grocery: grocery,
item: '',
brand: '',
units: 1,
quantity: 2,
isPurchased: false
}
class App extends Component {
state = initialValue;
handleChange = (e) => {
// added a spread iterator
this.setState({...this.state, [e.target.id]: e.target.value })
}
reset = ()=> {this.setState(initialValue)} // set to initialValue is clearing current state to initial state

how I place this.state inside ""?

here, I want access to 'this.state.select1' & 'this.state.select2' as factor's object attributes, in the handleClick event handler. how I place these in "", in the way that not become string? because output give me NaN.
This is the desired part of my code:
const factor = {
kilometer: 1,
meter: 1000,
centimeter: 100000,
millimeter: 1000000
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
text: '',
select1: '',
select2: '',
result: 0
}
}
handleChange1 = (e) => {
this.setState({
text: e.target.value
}
);
}
handleChange2 = (e) => {
this.setState({
select1: e.target.value
}
);
}
handleChange3 = (e) => {
this.setState({
select2: e.target.value
}
);
}
handleClick = () => {
this.setState({
result: (parseInt(this.state.text) * factor['this.state.select1']) /
factor['this.state.select2']
});
}
output:
enter image description here

Cannot read property 'files' of undefined for sending multiple images

Code
class Add_Give_Item_Form extends Component {
constructor(props) {
super(props);
this.state = {
// #インプット情報用
info: {
name: '',
owner: '',
keyword1: '',
keyword2: '',
keyword3: '',
bland: '',
state: '未使用、新品',
category: '',
images: [],
detail: '',
},
// Validation用
//  urlは必須項目ではないのでValidationには含めない
message: {
name: '',
keyword1: '',
keyword2: '',
keyword3: '',
state: '',
category: '',
detail: '',
},
allCategory: null,
allBland: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleImageSelect = this.handleImageSelect(this);
}
////
...
////
handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
const { info, message } = this.state;
this.setState({
info: { ...info, [name]: value },
});
this.setState({
message: { ...message, [name]: this.validator(name, value) },
});
};
handleImageSelect = (e) => {
this.setState({
info: { ...this.state.info, images: [...this.state.info.images, e.target.files] },
});
};
render() {
const { info, message, allCategory, allBland } = this.state;
// setStateが完了するまではnullにする。
if (this.state.allCategory === null || this.state.allBland === null) {
return <CircularProgress />;
} else {
return (
<div>
///////
.....
///////
<label>Images</label>
<input type="file" multiple onChange={this.handleImageSelect} />
What I want to do
I would like to catch each file sent by a user and put into state as this.state.info.images which is an array.
I saw some questions on stackoverflow and then I found some solutions. When I wrote the same code as what I saw, I got an error like below.
cannot read property files of undefined
I should write the same code but I got the error for some reasons.
I may take another way to realize what I want to do, but I want to write readable codes and figure out why it is happening.
I would like you to teach me why this happens and solutions.
Thank you very much.
I just notice I didn't put bind with this.handleImageSelect = this.handleImageSelect(this).
Now it works well.
Thank you very much.

How to eliminate Boilerplate caused by too many onChange methods in react component

I've been writing React component which is responsible for managing Book Add Form as well as Book Edit Form. At some point, it ended up with 300+ lines of codes. What bothers me the most is this code:
Book Title Is Changed In Form:
onChangeBookTitle(event) {
this.props.onChangeBookTitle(event.target.value);
if (event.target.value.length > 0) {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
title: ""
}
}));
} else {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
title: "Title Cannot Be Empty"
}
}));
}
}
Book Author Is Changed In Form :
onChangeBookAuthor(event) {
this.props.onChangeBookAuthor(event.target.value);
if (event.target.value.length > 0) {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
author: ""
}
}));
} else {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
author: "Author Cannot Be Empty"
}
}));
}
}
Book Date Is Changed In Form:
onChangeBookDatePicker(date) {
this.props.onChangeBookDatePicker(date);
if (date.length > 0 && moment(date, "YYYY-MM-DD", true).isValid()) {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
date: ""
}
}));
} else {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
date: "Please Pick a Publish Date"
}
}));
}
}
I wonder if there is a better way to organise / eliminate the code.
ideas ?
You can definitely refactor the repeating parts of the code away. For example, let's take the first two event handlers, and see how we can refactor them:
onChange(propHandler, field, errorMsg, event){
this.props[propHandler](event.target.value);
if (event.target.value.length > 0) {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
[field]: ""
}
}));
} else {
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
[field]: errorMsg
}
}));
}
}
onChangeBookTitle(event) {
return onChange('onChangeBookTitle', 'title', 'Title Cannot Be Empty', event);
}
onChangeBookAuthor(event) {
return onChange('onChangeBookAuthor', 'author', 'Author Cannot Be Empty', event);
}
As you can see, most of the code can become generic and only the specifics are separated to each handler.
If there are other changes (such as the predicate in the third handler), those can be incorporated generically in much the same way.
Also, this refactor is not finished, since the setState function argument is also almost the same, so that can be refactored as well:
onChange(propHandler, field, errorMsg, event){
this.props[propHandler](event.target.value);
const fieldErrMessage = event.target.value.length > 0 ? "" : errorMsg;
this.setState(prevState => ({
errorMsg: {
...prevState.errorMsg,
[field]: fieldErrMessage
}
}));
}
onChangeBookTitle(event) {
return onChange('onChangeBookTitle', 'title', 'Title Cannot Be Empty', event);
}
onChangeBookAuthor(event) {
return onChange('onChangeBookAuthor', 'author', 'Author Cannot Be Empty', event);
}

ReactJS - setting an inline style equal to a property on state is not working. What's going on?

I'm trying to get a FormWarning to display when users input incorrect information, but it seems to have disappeared on me. I'm trying to control whether or not it displays with this.state.formWarning.display - when the validateInputs function runs, if it determines an input is invalid, it should change the value of display from 'none' to 'block'. I'm trying to set the style for the Component to having a display that matches this.state.formWarning.display, but I am getting an error. Is my belief that you can set the styles for a component inline via an object not correct? Getting bugs regardless. ie
export default class FormOne extends React.Component {
constructor(props) {
super(props)
this.state = {
formOne: {
shippingAddress: {
firstName: '',
lastName: '',
address1: '',
city: '',
state: '',
zip: '',
country: 'US'
},
phone: '',
email: ''
},
formWarning: {
text: '',
invalidInputID: '',
display: 'block'
},
isSubmitted: false,
submitting: false
}
this.styles = this.props.styles || {}
}
componentWillReceiveProps(nextProps) {
if(nextProps.state.stepOne &&
nextProps.state.stepOne.formOneResponse) {
let formOneResponse = nextProps.state.stepOne.formOneResponse
formOneResponse.status === "delayed" || formOneResponse.status === "success"
? this.setState({isSubmitted: true})
: alert(formOneResponse.errorMessage)
this.setState(state => ({submitting: false}))
}
}
validateInputs = (inputs) => {
let { email, phone, shippingAddress } = inputs,
shippingKeys = Object.keys(shippingAddress)
console.log('validate inputs is firing')
for(let i = 0; i < Object.keys(shippingAddress).length; i++) {
let key = shippingKeys[i], input = shippingAddress[key]
if(!input) {
return this.showFormWarning(key)
}
}
if(!phone) return this.showFormWarning('phone')
if(/\S+#\S+\.\S+/.test(email)) return
this.showFormWarning('email')
return true
}
showFormWarning = key => {
clearTimeout(this.warningTimeout)
console.log('showformwarnign is firing')
this.setState(state => ({
formWarning: {
...state.formWarning,
text: 'Please fill out this field',
invalidInputID: key,
display: 'block'
}
}))
this.warningTimeout = setTimeout(() => {
this.setState(state => ({
formWarning: {
...state.formWarning,
display: 'none'
}
}))
}, 5000)
return false
}
saveInputVal = (event) => {
let { formOne: tempFormOne } = this.state,
input = event.currentTarget
console.log('saveinputvals is firing')
if(input.name === 'phone' || input.name === 'email') {
this.setState(state => ({
formOne: {
...state.formOne,
[input.name]: input.value
}
}))
} else {
this.setState(state => ({
formOne: {
...state.formOne,
shippingAddress: {
...state.formOne.shippingAddress,
[input.name]: input.value
}
}
}))
}
}
submit = (event) => {
event.preventDefault()
if(!this.validateInputs(this.state.formOne)) return
this.setState(state => ({submitting: true}))
this.props.saveShippingData(this.state.formOne)
this.props.stepOneSubmit(this.state.formOne)
}
render() {
if (this.state.isSubmitted) return <Redirect to="/order" />
let CustomTag = this.props.labels ? 'label' : 'span',
{ inputs, saveInputVal, styles, state } = this,
{ formWarning, submitting } = state,
{ invalidInputID, text, display } = formWarning
return (
<div style={this.styles.formWrapper}>
{
typeof this.props.headerText === 'string'
? ( <h2 style={this.styles.formHeader}>
{this.props.headerText}</h2> )
: this.props.headerText.map((text) => {
return <h2 key={text} style={this.styles.formHeader}
className={'header'+this.props.headerText.indexOf(text)}>{text}</h2>
})
}
<form onSubmit={this.submit} style={this.styles.form}>
<FormOneInputs inputs={inputs} saveInputVal={saveInputVal}
CustomTag={CustomTag} styles={styles} />
<button style={this.styles.button}>{this.props.buttonText}
</button>
</form>
<Throbber throbberText='Reserving your order...' showThrobber=
{submitting} />
<FormWarning style={display: {this.state.formWarning.display}} invalidInputID={invalidInputID} text={text}/>
</div>
)
}
}
You don't need to set any CSS class. The approach is as follows:
(1) Given a component you want to render or not render depending on a variable
(2) Make a helper method that checks for the condition and returns the actual component if you want it rendered. Otherwise, do nothing (basically returns undefined)
(3) Call that method from wherever you want the component to possibly appear.
Concrete example:
class FormOne extends React.Component {
// (...) all other things omitted to focus on the problem at hand
renderFormWarning() {
if (formIsInvalid) {
return <FormWarning ... />;
}
// else won't do anything (won't show)
}
render() {
return (
{/* ... */}
{this.renderFormWarning()}
);
}
}
In the above example, replace formIsInvalid with some statement that will tell you if the form is invalid. Then, if that condition is true, it will return the FormWarning component. Otherwise, no form warning will be shown. From the render() method, all you need do is call that helper method.

Resources