sah
sah

Reputation: 165

Update happening before state change due to promise?

I have this update function that is supposed to update the state and the view of the component whenever 'Update' button is clicked; however, it only starts to update after 'Update' button is clicked. Like, I have to click update then change the form inputs to see the change of the view.

Expectation: 

 Step 1: Change Form input then click 'Update' button
 Step 2: State and View changes

Reality/Issue:

 Step 1: In order to see the change, I have to click the 'Update' button first
 Step 2: Then I can change Form input and see the change in my view.

How do I make it that state and the view of the component is changed only after 'Update' button is clicked?

I found that Promises are asynchronous, so I tried adding call-backs, used async await, or moved orders of the codes around, but it still produced the same issue.

export class EducationPage extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        incomingClass: {...this.props.location.state.data},
        alert: {
            display: false
        }};
    this.updateEdu = this.updateEdu.bind(this);
    this.handleChange = this.handleChange.bind(this);
}   

handleChange = (event) => {
    const target = event.target;
    const value =  target.value;
    const name = target.name;
    this.setState((prevState) => {
        let newState = {};
        let data = Object.assign({}, prevState.data);
        data[name] = value;
        newState.data = data;
        return newState;
    });
};

updateEdu = (e) => {
    e.preventDefault();
    let newEdu = {...this.state.incomingClass};
    BackEndRestPromiseService.updateEdu(newEdu).then(data => { // Promise
        this.setState({
            incomingClass: data
        }, () => console.log(data));
    }).catch(e => {
    console.log(e);
        this.setState({
            error: "Error!"
        });
    });
}

render() {
return (
    <div>
        <Form onSubmit={e => this.updateEdu(e)}>
        <Button type="submit">Update</Button>
            <Form.Row>
                <Form.Group as={Col}>
                    <Form.Label>School</Form.Label>
                    <Form.Control id="school" name="school" placeholder="School" value={this.state.incomingClass.school || ""} onChange={this.handleChange}/>
                </Form.Group>

                <Form.Group as={Col}>
                    <Form.Label>Grade</Form.Label>
                    <Form.Control id="grade" name="grade" placeholder="Grade #" value={this.state.incomingClass.grade || ""} onChange={this.handleChange}/>
                </Form.Group>
            </Form.Row>
        </Form>
    </div>
)
}

Upvotes: 0

Views: 98

Answers (1)

Avin Kavish
Avin Kavish

Reputation: 8947

I'm going to simplify some of your code to make it easier to debug.

handleChange = (event) => {
    const { name, value } = event.target;
    this.setState(prevState => 
      ({ incomingClass: { ...prevState.incomingClass, [name]: value } }));
};

What I noticed here is that you have no data property in you initial state, only incomingClass. but your handleChange method operates on prevState.data. Also setState supports partially updating state. So you don't have to get the full previous state and set it.

Also, there is no need to rebuild incomingClass before sending it to the server.

updateEdu = (e) => {
    e.preventDefault();
    BackEndRestPromiseService.updateEdu(this.state.incomingClass)
     .then(data => this.setState({ incomingClass: data }))
     .then(() => console.log(data))
     .catch(e => { console.log(e); this.setState({ error: "Error!" }) });
}

Since you have already use class properties, there is no need to use a lambda here nor bind it.

<Form onSubmit={this.updateEdu}>

This is unnecessary since you are using class properties

this.updateEdu = this.updateEdu.bind(this);
this.handleChange = this.handleChange.bind(this);

Upvotes: 2

Related Questions