使用setState方法添加子对象

问题描述 投票:0回答:1

我正在尝试使用this.setState应用程序中的expo方法将新的子对象添加到现有对象。单击按钮后将添加子对象,该按钮将更新构成子对象的字段。

这是我的代码:

import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ImageBackground } from 'react-native';

import CenteredButton from '../components/CenteredButton';
import { Actions } from 'react-native-router-flux';

var t = require('tcomb-form-native');
var _ = require('lodash');

const Form = t.form.Form;
const stylesheet = _.cloneDeep(t.form.Form.stylesheet);

stylesheet.textbox.normal.borderColor = '#b3b3b5';
stylesheet.textbox.normal.fontFamily = 'RobotoThin';
stylesheet.textbox.normal.backgroundColor = '#fdfdfd';
stylesheet.textbox.normal.fontSize = 18;
stylesheet.textbox.normal.borderWidth = 0.6;
stylesheet.textbox.normal.borderRadius = 10;

stylesheet.textbox.error.fontFamily = 'RobotoThin';
stylesheet.textbox.error.backgroundColor = '#fdfdfd';
stylesheet.textbox.error.fontSize = 18;
stylesheet.textbox.error.borderWidth = 0.6;
stylesheet.textbox.error.borderRadius = 10;

const Email = t.refinement(t.String, email => {
  const regex = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; 
  return regex.test(email);
});

const EmailTo = t.struct({
  emailPerson: Email,
  emailInsurance:  t.maybe(Email)
});

const options = {
  auto: 'none',
  stylesheet: stylesheet,
  fields: {
    emailPerson: {
      placeholder: 'Email personale',
      autoCapitalize: 'none',
      autoCorrect: false,
    },
    emailInsurance: {
      placeholder: 'Email Assicurazione',
      autoCapitalize: 'none',
      password: true,
    }
  }
}

export default class NessunProblema extends Component {

  constructor(props) {
    super(props);
    this.state = {
      emails: {
        emailPerson: '',
        emailInsurance: ''
      },
      ascertainment: { }
    }
  }

  componentDidMount() {
    this.setState({ ascertainment: this.props.ascertainment });
  }

  _onChange = (emails) => {
    this.setState({ emails });
  }

  _handle = () => {
    const value = this.refs.form.getValue();
    if ( value ) {
      this.setState(prev => ({
        ascertainment: {
          ...prev.ascertainment,
          emails: {
            ...prev.ascertainment.emails,
            emailPerson: value.emailPerson,
            emailInsurance: value.emailInsurance
          }
        }
      }));
    }

    console.log(this.state.emails);
    console.log(this.state.ascertainment);
  }

  render() {
    return (
      <View style={{flex: 1, backgroundColor: 'white' }}>
        <ImageBackground source={require('../images/NoProblem.png')} style={styles.backgroundImage}>
          <View style={{ flex: 2, alignItems: 'center', justifyContent: 'center', width: '100%', paddingHorizontal: 20, top: 10}}>
            <Text style={styles.domanda}>
              Text
            </Text>
            <Text style={styles.domanda2}>
              Text
            </Text>
          </View>

          <View style={{padding: 20}}>
            <Form 
              ref='form'
              options={options}
              type={EmailTo}
              value={this.state.emails}
              onChange={this._onChange}
            />
          </View>

          <CenteredButton
            next={ this._handle }
          />
        </ImageBackground>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  domanda: {
    color: '#00b0ff',
    textAlign: 'center',
    fontSize: 44,
    fontFamily: 'RobotoRegular',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 20
  },
  domanda2: {
    color: 'black',
    textAlign: 'center',
    fontSize: 22,
    fontFamily: 'RobotoRegular',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 20
  },
  testoRosso: {
    color: '#f32a19',
    fontFamily: 'RobotoRegular',
  },
  backgroundImage: {
    flex: 1,
    resizeMode: 'cover'
  },
  textInput: {
    width: '100%',
    paddingHorizontal: 15,
    height: 40,
    marginBottom: 20,
    fontSize: 18,
    borderWidth: 0.6,
    borderColor: 'black',
    borderRadius: 10,
    color: 'black',
    fontFamily: 'RobotoThin',
    backgroundColor: 'white'
  },
});

我注意到,如果我单击TWO两次并按AVANTI按钮,则会得到正确的结果。但是,为什么?

我遵循此answer,但不能解决问题。

javascript react-native expo
1个回答
1
投票

问题是setState()不同步,值被异步更新

setState()不会立即使this.state发生突变,但会创建一个挂起的状态转换。调用此方法后访问this.state可能会返回现有值。无法保证对setState的调用的同步操作,并且可能为提高性能而对调用进行批处理。

_handle = () => {
    const value = this.refs.form.getValue();
    if ( value ) {
      this.setState(prev => ({
        ascertainment: {
          ...prev.ascertainment,
          emails: {
            ...prev.ascertainment.emails,
            emailPerson: value.emailPerson,
            emailInsurance: value.emailInsurance
          }
        }
      }));
    }

    console.log(this.state.emails); // will be the emails in the previous state, since setState has not been called yet by react 
    console.log(this.state.ascertainment); // if you click twice, you are still getting the `last` state, but since it is the same as the state you are setting the second time, you get the wrong idea that it is being set if you click twice!
  }
© www.soinside.com 2019 - 2024. All rights reserved.