react-native

Why do my React Native input fields constantly reset to their initial values?


I have a few screens in my React Native app where I want to receive some user input, but on these screens I also want to start with initial values in the fields when the user first comes to visit the screen, especially if they are updating existing data. I can't see how to do this, because the moment I provide a default value the inputs seem to cease to be editable. On Picker controls, they automatically reset themselves to the original value, on TextInput fields they reset themselves to default after a momentary blink.

In the event handlers I can see the changed value being received but that data is not passed back to the dropdown, even though the default values are configured to reference the same object that I am updating in the event handler.

This code reproduces the problem I am seeing:

import {Picker} from '@react-native-picker/picker';
// You can import from local files
import AssetExample from './components/AssetExample';

// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';

export default function App() {

  const scores = {
    positive: 1,
    negative: 2
  };

  const setScore = function(direction, scoreText) {
    console.log("Set "+direction+" to "+score+" currently: "+JSON.stringify(scores));
    let score = parseInt(scoreText);
    if ( direction == 'positive' ) {
      scores.positive = score;
    } else {
      scores.negative = score;
    }
  }

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>
        Select a different option in this dropdown and watch in astonishment as nothing happens!
      </Text>
      <Picker 
          onValueChange = { (itemValue, itemIdx) => setScore('positive', itemValue)} 
          selectedValue={scores.positive}
          >
            <Picker.Item key="1-0" label="0" value="0" />
            <Picker.Item key="1-1" label="1" value="1" />
            <Picker.Item key="1-2" label="2" value="2" />
            <Picker.Item key="1-3" label="3" value="3" />
            <Picker.Item key="1-4" label="4" value="4" />
       </Picker>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

This is visible in a working Snack here.

I can't see this problem showing up elsewhere so it is probably a fundamental misunderstanding on my part about how the React Native Input system is supposed to operate. How can I use Input fields to receive input from my users while having a default value selected when the screen is first loaded?


Solution

  • You have to use useState hook to track values mutable by user, as well as any dynamically changing values inside functional components. So instead of declaring scores as

    const scores = {
      positive: 1,
      negative: 2
    };
    

    we can use useState hook

    import React, { useState } from 'react'
    ...
    const [scores, setScores] = React.useState({
      positive: 1,
      negative: 2
    })
    

    You declare them with initial values, and it returns the current state and setScores function that updates the state, so you can then set your state as

    if ( direction == 'positive' ) {
      setScores({positive: score})
    } else {
      setScores({negative: score})
    }