You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native函数组件输入时防止其他组件数据清空求助

Hey there, let's tackle this issue head-on—your gallery and state data are getting wiped because of how you're updating your component state. Here's what's happening and how to fix it:

The Root Problem

In React Native functional components, the setState setter from useState doesn't automatically merge object properties (unlike class components' this.setState). When you call setState({text}) or setState({selectedIncidence: itemValue}), you're replacing the entire state object with a new one that only has the single property you just set. That means your photos array (and any other existing state fields) get dropped entirely, causing the gallery to empty on re-render.

The Solution: Merge State Properly

Every time you update state, you need to preserve the existing state properties while adding/updating the new one. Use the spread operator (...) to copy all existing state fields, then overwrite the specific property you want to change. For even more reliability (especially if your new state depends on the previous state), use the functional update form of setState.

Modified Code with Fixes

Here's your component code updated to fix the state merging issue:

export default function EvidenceSubmission ({route, navigation, navigation:{setParams}}){ 
  // Incidence 
  const [state, setState]= useState({ 
    selectedIncidence: 'select incidence', 
    photos:[], 
    text: '', // Initialize text field to avoid undefined warnings
  }); 

  /** 
   * clears images in async storage 
   */ 
  const clearStorage= async() =>{ 
    try{ 
      await AsyncStorage.clear(); 
    } catch(exception){ 
      console.log('error clearing items'); 
    } 
    console.log('items cleared (Evidence Page)'); 
  } 

  useEffect(()=> { 
    /*Get images from async storage*/ 
    const getData = async () => { 
      try { 
        const value = await AsyncStorage.getItem('photos') 
        if(value !==null){ 
          setState(prevState => ({ 
            ...prevState, // Preserve existing state
            photos: (JSON.parse(value)).reverse(), 
          })); 
        } 
      }catch(e){ 
        console.log('error with async getData'); 
      } 
    } 
    getData(); 
  }, []); 

  /* navigates to photo preview page */ 
  const navigateToPhotoPreview = (path) =>{ 
    navigation.navigate('PhotoPreviewer', { 
      transferredImageItem: path, 
    }) 
  } 

  return( 
    <SafeAreaView style= {globalStyle.MainContainer}>
      <StatusBar barStyle="light-content" backgroundColor="#174060"/>
      <View flexDirection='column' flex={0.456} marginTop={30} marginRight ={5} marginLeft ={5} borderWidth={0.5} borderRadius={3} borderColor='#7E7E7E'>
        <View>
          <FlatList data= {state.photos} keyExtractor={(item, index)=> index.toString()} 
            renderItem={ ({ item}) => ( 
              <TouchableOpacity onPress={() => navigateToPhotoPreview(item) }>
                <Image style={{ width:70, height:75,margin:0.5, resizeMode:'cover'}} source = {{ uri: "file://"+ item}} />
              </TouchableOpacity>
            ) } numColumns = {5} />
        </View>
      </View>
      <TouchableOpacity style={styles.addPhotoButton} onPress={()=>{navigation.goBack()}}>
        <Add name={'add'} size={30} color="white" />
      </TouchableOpacity>
      <View style={{justifyContent: 'center', margin:5 ,flex: 1.2}}>
        <View style={{borderWidth: 1, borderColor:'#C4C4C4', borderRadius:5, width: 270, marginLeft: 5, marginBottom: 0, marginTop: 15}}>
          <Picker selectedValue ={state.selectedIncidence} style={{height:45, width: 270, fontFamily:'roboto', fontStyle:'normal', fontWeight:'normal'}} 
            onValueChange={(itemValue, itemIndex) => 
              // Merge existing state with new selectedIncidence
              setState(prevState => ({ ...prevState, selectedIncidence: itemValue })) 
            } >
            <Picker.Item label="Non-Compliance" value="Non-Compliance"/>
            <Picker.Item label="Logistics" value="Logistics"/>
            <Picker.Item label="Harassment" value="Harassment"/>
          </Picker>
        </View>
        <View marginBottom={0} marginLeft={5} marginTop={15}>
          <Text style={styles.textStyle}> Description </Text>
        </View>
        <View style={{flexDirection:'row'}} >
          <View>
            <TextInput style={{height: 70, width: 270, borderRadius: 8, borderColor:'#C4C4C4', borderWidth: 1, marginLeft: 5}} 
              onChangeText={(text) => 
                // Merge existing state with new text value
                setState(prevState => ({ ...prevState, text }))
              } 
              value={state.text} 
              multiline={true} 
              enablesReturnKeyAutomatically={true}>
            </TextInput>
          </View>
          <TouchableOpacity style={styles.microphoneButton}>
            <Microphone name="microphone" size={21} color='white' />
          </TouchableOpacity>
        </View>
        <View marginBottom={0} marginLeft={0} marginTop={15} marginBottom={15} >
          <View style={{flexDirection: 'row'}}>
            <Text style={{margin:10,marginRight:20, fontFamily:'roboto', fontSize: 14, fontWeight:'bold', }}> Submit as </Text>
            <View style={styles.radioCircumference}>
              <TouchableOpacity style={styles.radioButton}></TouchableOpacity>
            </View>
            <Text style={{marginLeft: 5, marginRight: 0, marginTop: 10}}>anonymous</Text>
            <Text style={{marginLeft: 10, marginRight: 10, marginTop: 10, fontWeight:'bold'}}> or </Text>
            <View style={styles.radioCircumference}>
              <TouchableOpacity style={styles.radioButton}></TouchableOpacity>
            </View>
            <Text style={{marginTop: 10,marginLeft: 5, marginRight: 0}}>Sign In</Text>
          </View>
        </View>
        <TouchableOpacity style={styles.button} onPress={()=>clearStorage()} >
          <Text style={{color:'white', alignSelf:'center', fontSize: 18, }}> Next </Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  ); 
}

Key Changes Made

  1. Added text to initial state: Prevents undefined warnings when the TextInput first renders.
  2. Merged state in setState calls:
    • For the Picker's onValueChange, we use setState(prevState => ({ ...prevState, selectedIncidence: itemValue })) to keep existing state while updating the selected incidence.
    • For the TextInput's onChangeText, we use setState(prevState => ({ ...prevState, text })) to preserve the photos array and selectedIncidence value when updating the description text.
  3. Updated keyExtractor: Changed index to index.toString() because FlatList keys need to be strings (avoids warnings).

Why This Works

The spread operator (...prevState) copies all properties from the previous state object into a new one. We then overwrite only the specific property we want to update, ensuring no existing state data (like your photos array) gets lost during state updates.

内容的提问来源于stack exchange,提问作者Immanuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 10:38:12