React native динамически созданные компоненты не отображаются при первом нажатии

Я пытаюсь создать список, динамически добавляя элементы списка в массив в state, а затем используя оператор map для их перебора. Однако новые элементы списка отображаются только после второго щелчка по кнопке, которая обрабатывает метод setState. Любые указатели на решение этой проблемы?

...
constructor(props) {
    super(props);
    this.state = {
        requirements:[], // Placeholder array in state
        currentRequirement
    }
}
...

И в моем методе render у меня вот такое.

{
    this.state.requirements.map((el,i) => (
        <TouchableOpacity key={i}>
         <BulletItem text={el}/>
        </TouchableOpacity>
    ))
}
<FormInput 
    onChangeText={(value) => { 
        this.setState({ currentRequirement: value})}
    } 
    placeholder="Enter a new requirement"
/>

<Button 
    title="Add Requirement" 
    onPress={() => {
             this.onAddRequirementComponent()
    }}
/>

Метод обращения с setState таков.

onAddRequirementComponent() {
    this.setState(previousState => ({
        requirements: [...previousState.requirements, this.state.currentRequirement],
        currentRequirement:''
    }))
}

ОБНОВЛЕНИЕ: ПОЛНЫЙ КОМПОНЕНТ

import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView, Picker, TouchableOpacity } from 'react-native';
import { BulletItem, TagCloud } from "../components/index";
import { Actions } from "react-native-router-flux";
import {
    Button,
    Header,
    FormInput,
    FormLabel,
} from 'react-native-elements';
export default class ListScreen extends Component {

    constructor(props) {
        super(props);
        this.state = {
            jobtype: '',
            level: '',
            requirements: [],
            benefits: [],
            currentRequirement: '',
            currentBenefit: ''
        }
    }
    render() {
        return (
            <View style={styles.container}>
                <Header
                    backgroundColor='#fff'
                    borderBottomWidth={0}
                    leftComponent={{ icon: 'corner-up-left', color: '#333', type: 'feather', onPress: () => { Actions.pop() } }}
                    centerComponent={{ text: 'Create New Job', fontFamily: 'VarelaRound-Regular', style: { color: '#333', fontSize: 18 } }}
                    rightComponent={{ icon: 'options', color: '#333', type: 'simple-line-icon' }} />
                <ScrollView>
                    <FormLabel>Job Title</FormLabel>
                    <FormInput placeholder="e.g. Full Stack Javascript Developer"/>
                    <FormLabel >REQUIREMENTS</FormLabel>
                    {
                        this.state.requirements.map((el, i) => (
                            <TouchableOpacity key={i}><BulletItem containerStyle={{ backgroundColor: '#EFF0F2', borderRadius: 4 }} style={{ backgroundColor: '#EFF0F2' }} text={el} /></TouchableOpacity>
                        ))
                    }
                                <FormInput 
                    onChangeText={(value) => { 
                        this.setState({ currentRequirement: value})}
                    } 
                    placeholder="Enter a new requirement"
                />

                <Button 
                    title="Add Requirement" 
                    onPress={() => {
                            this.onAddRequirementComponent()
                    }}
                />
                    <FormLabel style={{ fontFamily: 'VarelaRound-Regular', color: '#333' }} labelStyle={{ fontFamily: 'VarelaRound-Regular', color: '#333' }}>BENEFITS</FormLabel>
                    {
                        this.state.benefits.map((el, i) => (
                            <TouchableOpacity key={i}><BulletItem text={el} /></TouchableOpacity>
                        ))
                    }
                    <FormInput value={this.state.currentBenefit} onChangeText={(value) => { this.setState({ currentBenefit: value }) }} placeholder="3 years experience developing Javascript apps" />
                    <Button title="Add" onPress={() => { this.onAddBenefitComponent() }}/>
                    <Picker selectedValue={this.state.jobtype}
                        style={{ height: 50, width: '100%', backgroundColor: '#EFF0F2' }}
                        onValueChange={(itemValue, itemIndex) => this.setState({ jobtype: itemValue })}>
                        <Picker.Item label="Full Time" value="fulltime" />
                        <Picker.Item label="Part Time" value="parttime" />
                        <Picker.Item label="Contract" value="contract" />
                        <Picker.Item label="Remote" value="remote" />
                    </Picker>
                    <Picker selectedValue={this.state.level}
                        style={{ height: 50, width: '100%', backgroundColor: '#EFF0F2' }}
                        onValueChange={(itemValue, itemIndex) => this.setState({ level: itemValue })}>
                        <Picker.Item label="Junior" value="junior" />
                        <Picker.Item label="Mid-Level" value="mid" />
                        <Picker.Item label="Management" value="management" />
                        <Picker.Item label="Senior" value="senior" />
                    </Picker>
                </ScrollView>
            </View>
        );
    }

    onAddRequirementComponent() {
        if (this.state.currentRequirement)
            this.setState(previousState => ({
                requirements: [...previousState.requirements, this.state.currentRequirement],
                currentRequirement: ''
            }))
    }

    onAddBenefitComponent() {
        this.setState(previousState => ({
            benefits: [...previousState.benefits, this.state.currentBenefit],
            currentBenefit: ''
        }))

    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
    }
});

Если вы дважды нажмете кнопку, отобразятся ли 2 элемента или требуется 2 щелчка, чтобы только 1 элемент был добавлен в массив и повторно отрисован?

Tholle 10.08.2018 14:51

@Tholle после второго щелчка отображается только один элемент

fitzmode 10.08.2018 14:53

Хорошо, это расстраивает. Ваш setState выглядит правильно. Вы можете использовать previousState.currentRequirement, но проблема не в этом. Как реализован компонент Button? Возможно, он использует метод onPress по двойному щелчку.

Tholle 10.08.2018 14:59

@ Нажмите кнопку из библиотеки пользовательского интерфейса react-native-elements. Я заподозрил то же самое и поменял его на простой Text, но все равно не повезло. Я заподозрил задержку на моем эмуляторе Genymotion и запустил его на физическом устройстве - тоже не повезло.

fitzmode 10.08.2018 15:01

Хорошо. Не могли бы вы включить свой компонент целиком? Может быть, происходит что-то еще неуловимое.

Tholle 10.08.2018 15:02

@Thole также пытался принудительно выполнить повторный рендеринг с помощью this.forceUpdate(), но это тоже не сработало. На данный момент я абсолютно в тупике.

fitzmode 10.08.2018 15:03

А если вы укажете console.log(this.state.requirements); в начале метода рендеринга, он все равно не будет содержать элемент, пока вы не нажмете дважды? Очень странно.

Tholle 10.08.2018 15:25
0
7
472
1

Ответы 1

Это основная логическая часть, и она отлично работает. Я использовал только нативные элементы, такие как TextInput. Единственное изменение, которое я сделал, чтобы полностью контролировать TextInput, добавив value={this.state.currentRequirement} плюс предложение @Tholle для использования previousState.

class Test extends Component {
  state = {
    requirements: [],
    currentRequirement: ''
  }

  onAddRequirementComponent() {
    this.setState(previousState => ({
      requirements: [...previousState.requirements, previousState.currentRequirement],
      currentRequirement:''
    }))
  }

  render() {
    return(
      <View>
        <TextInput onChangeText={(value) => { 
          this.setState({ currentRequirement: value})}
        }
        value={this.state.currentRequirement}
        />

        { this.state.requirements.map((el,i) => (
            <Text key={i}>{el}</Text>
        ))}

        <Button 
          title="Add Requirement" 
          onPress={() => {
            this.onAddRequirementComponent()
          }}
        />
      </View>
    );
  }
}

Другие вопросы по теме