Varun Naharia
Varun Naharia

Reputation: 5420

How to access react-natve variable defined in constructor in render?

I am new to react native and facing problem in defining/accessing variable what I did is

  export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    const unit = [
      {label: 'mm', value: 'mm'},
      {label: 'cm', value: 'cm'},
      {label: 'meters', value: 'm'},
      {label: 'km', value: 'km'},
      {label: 'inches', value: 'in'},
      {label: 'feet', value: 'ft'},
      {label: 'yards', value: 'yd'},
      {label: 'miles', value: 'mi'},
      {label: 'nautical miles', value: 'nmi'},
    ];
    var selectedValue = 'mm';
  }

  render() {
    return (
      <View style={styles.screen}>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <View style={styles.body}>
            <View style={styles.rowContainer}>
              <Text style={styles.text}>Scale Ratio </Text>
              <TextInput style={styles.textInput}>1</TextInput>
              <TextInput style={styles.textInput}>12</TextInput>
            </View>
            <View style={styles.rowContainer}>
              <Text style={styles.text}>Real Length </Text>
              <TextInput style={styles.textInput}>120</TextInput>
              {/* <TextInput style={styles.textInput}>mm</TextInput> */}
              <View style={styles.container}>
                <Picker
                  selectedValue={selectedValue}
                  style={{height: 50, width: 150}}
                  onValueChange={(itemValue, itemIndex) =>
                    setSelectedValue(itemValue)
                  }>
                  {unit.map(item => (
                    <Picker.Item label={item.label} value={item.value} />
                  ))}
                </Picker>
                {/* <RNPickerSelect
                style={styles.textInput}
                onValueChange={value => console.log(value)}
                items={this.unit}
              /> */}
              </View>
            </View>
            <View style={styles.rowContainer}>
              <Text style={styles.text}>Scale Length </Text>
              <TextInput style={styles.textInput}>10</TextInput>
              <TextInput style={styles.textInput}>mm</TextInput>
            </View>
          </View>
        </ScrollView>
      </View>
    );
  }
}

But I am getting error

enter image description here

I am unable to access both unit and selectedValue

Upvotes: 0

Views: 733

Answers (2)

Max Starling
Max Starling

Reputation: 1037

JavaScript way (this)

Save it to this object (constructor creates and returns it).

/* inside of constructor */
this.selectedValue = 'mm';
/* outside of constructor, but inside of class mthods*/
console.log(this.selectedValue); // 'mm'
this.selectedValue = 'qq';

JavaScript way (static variable)

Save it as a static variable, that will be available outside of class.

/* inside of constructor */
HomeScreen.selectedValue = 'mm';
/* outside of constructor, inside AND outside of class*/
console.log(HomeScreen.selectedValue); // 'mm'
HomeScreen.selectedValue = 'qq';

JavaScript way (closure)

p.s. it's possible, but not recommended (not secure at all)

You could lift your variable declaration up moving it outside of your class. In this case all the class internals can take variable from closure and read/rewrite this variable.

React way (state)

If you want to see UI updates when you change variable, you have to use reactivity way (subscription on changes). Reacts provides it with props and state. If you want to handle internal reactive class variable, you should use state. In this case every time you change state, your React calls class render() method.

/* inside of constructor */
this.state = { selectedValue: 'mm' };
/* outside of constructor, inside of class methods */
console.log(this.state.selectedValue); // 'mm'
this.setState({ selectedValue: 'qq' });

tip with setState

Method this.setState is async, React handles this method in async way to do some optimizations batching many updates together.

So if you have code like this in a class method, you may get the result below. (update isn't immediate)

this.setState({ selectedValue: 'qq' });
console.log(this.state.selectedValue) // 'mm'

But your render() method will handle it correctly.

render() {
  console.log(this.state.selectedValue); // 'qq'
  /* ... */
}

Upvotes: 1

norbitrial
norbitrial

Reputation: 15166

Instead you can use states so you can access in your component's render part.

Initiate in the constructor your component state as follows:

constructor(props) {
    super(props);

    this.state = {
      unit: [
         /* your items */
      ],
      selectedValue: 'mm'
    }
}

Then you can access as this.state.unit or this.state.selectedValue.

For example in <Picker /> component like the following:

<Picker selectedValue={this.state.selectedValue}
        style={{height: 50, width: 150}}
        onValueChange={(itemValue, itemIndex) =>
        setSelectedValue(itemValue)
}>
    {unit.map(item => <Picker.Item label={item.label} value={item.value} /> )}
</Picker>

I suggest to to read through especially the Adding Local State to a Class part of React docs.

I hope this helps!

Upvotes: 1

Related Questions