I need help with updating the state in React.
I am making an Encryption/Decryption form with React. This EncryptForm is rendered in App.js. What I want to do is listen to onSubmit
function and update the isSubmitted state, then render decipher
value under the 'Convert' button.
My question is why .setState
works in handleChange
method but it doesn't work in handleSubmit
method. What am I missing?
(encryptMessage
and decryptMessage
methods are working fine.)
Here is the EncryptForm component code.
import React, { Component } from 'react'
import crypto from 'crypto'
class EncryptForm extends Component {
state = {
userInput: '',
isSubmitted: false,
decipher: ''
}
encryptMessage(input, key) {
// Initialization Vector - 16 bytes
const iv = new Buffer(crypto.randomBytes(16), 'utf8')
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)
let encoded = cipher.update(input, 'utf8', 'base64')
encoded += cipher.final('base64')
return [encoded, iv, cipher.getAuthTag()]
}
decryptMessage(key, encoded, iv, authTag) {
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
decipher.setAuthTag(authTag)
let text = decipher.update(encoded, 'base64', 'utf8')
text += decipher.final('utf8')
return text
}
/*
Non-encryption methods
*/
handleSubmit = event => {
event.preventDefault()
const KEY = new Buffer(crypto.randomBytes(32), 'utf8')
const [encrypted, iv, authTag] = this.encryptMessage(this.state.userInput, KEY)
const decrypted = this.decryptMessage(KEY, encrypted, iv, authTag)
const newState = {
...this.state,
isSubmitted: true,
decipher: decrypted
}
// THIS IS NOW UPDATING THE STATE :(
this.setState({ newState })
}
handleChange = event => {
this.setState({
[event.target.name]: event.target.value,
})
}
render() {
const { userInput, isSubmitted, decipher } = this.state
const isInvalid = userInput === ''
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
name='userInput'
placeholder='Encrypt this text...'
onChange={this.handleChange}
/>
<button disabled={isInvalid} type='submit'>Convert</button>
{isSubmitted && <p>{decipher.value}</p>}
</form>
)
}
}
export default EncryptForm
Thank you!
You are setting state incorrectly in handleSubmit
. newState
is the entire state object, so setting it like this.setState({ newState })
is not updating the whole state, but instead creating a new key called newState
and setting it to what you expect the state to be. The result is something like this:
state = {
...previous_state,
newState: {
...this.state,
isSubmitted: true,
decipher: decrypted
},
}
Instead you could do something like this to correctly update:
// desctructure so it overwrites each key
this.setState({ ...newState });
// pass the non-nested object
this.setState(newState);
Or the preferred method would be to only update the keys necessary. this.setState
does a shallow merge with the given object and the previous state. So you don't need to do {...this.state}
(in fact it is discouraged).
This is the most concise and accurate way:
this.setState({ isSubmitted: true, decipher: decrypted });