Реакция - .setState частично не работает - PullRequest
0 голосов
/ 07 марта 2020

Мне нужна помощь с обновлением состояния в React. Я делаю форму шифрования / дешифрования с помощью React. Этот EncryptForm отображается в приложении. js. Я хочу прослушать функцию onSubmit и обновить состояние isSubmitted, а затем визуализировать значение decipher под кнопкой «Преобразовать».

У меня вопрос , почему .setState работает в handleChange метод, но он не работает в handleSubmit методе. Что мне не хватает? (encryptMessage и decryptMessage методы работают нормально.)

Вот код компонента EncryptForm.

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

Спасибо!

1 Ответ

1 голос
/ 07 марта 2020

Вы неправильно устанавливаете состояние в handleSubmit. newState - это весь объект состояния, поэтому установка его как this.setState({ newState }) не обновляет все состояние, а создает новый ключ с именем newState и устанавливает его в ожидаемое состояние. В результате получается что-то вроде этого:

state = {
  ...previous_state,
  newState: {
    ...this.state,
    isSubmitted: true,
    decipher: decrypted
  },
}

Вместо этого вы можете сделать что-то подобное для правильного обновления:

// desctructure so it overwrites each key
this.setState({ ...newState });

// pass the non-nested object
this.setState(newState);

Или предпочтительным методом будет обновить только необходимые ключи. this.setState выполняет поверхностное слияние с данным объектом и предыдущим состоянием. Так что вам не нужно делать {...this.state} (на самом деле это не рекомендуется).

Это самый лаконичный и точный способ:

this.setState({ isSubmitted: true, decipher: decrypted });
...