Search code examples
javascriptreactjsreact-nativepicker

React-Native Picker TypeError: Cannot read property 'map' of undefined


I am trying to display data in picker (react-native) but the above error is displaying if I try to map the this.state.dataSource I don't understand what seems to be the problem

I have tried almost all the same type questions on Stackoverflow but none of them seems to work

 constructor() {
        super()
        this.state = {
            dataSource: [],
            PickerValueHolder: '',

        }

    }

componentDidMount() {

  var path = RNFS.DocumentDirectoryPath + '/defects/' + 'defects'+ '.json';
  console.log(path);
  // write the file
  return RNFS.readFile(path, 'utf8')
    .then((success) => {
      newData = JSON.parse(success);
      dataSource = newData[0].results.recordset;
      dataSource = JSON.stringify(dataSource)
      console.log("datasource "+dataSource); 
      this.setState({
        isLoading: false,
        dataSource
      });
    })
    .catch((err) => {
      console.log(err.message);
    });
}

console.log("datasource "+dataSource); output

[{"success":true,"results":{"recordsets":[[{"DefectID":2,"Defect":"Damage","Description":"Crack in walls"}]],"recordset":[{"DefectID":2,"Defect":"Damage","Description":"Crack in walls"}],"output":{},"rowsAffected":[1],"returnValue":0}}]

Picker code

<Picker
  selectedValue={this.state.PickerValueHolder}
  style={{ height: 50, width: 100 }}
  onValueChange={
    (itemValue, itemIndex) => this.setState({ PickerValueHolder: itemValue })}
>
  {console.log("Picker " + this.state.dataSource)}
  {this.state.dataSource.map((item, key) => {
    <Picker.Item label={item.defect} value={item.defect} key={key} />
    }
  )}
</Picker>

{console.log("Picker " + this.state.dataSource)} output

[{"DefectID":2,"Defect":"Damage","Description":"Crack in walls"}]

error TypeError: Cannot read property 'map' of undefined

Expected output: the data should get inflated in picker


Solution

  • Because RNFS.readFile(path, 'utf8') is async, the render method will most likely be called before this.state.dataSource has been populated. this.state.dataSource will be null initially, so you need to set that within your constructor.

    // ...
    constructor() {
      this.state = {
        dataSource: []
      }
    }
    

    Update

    Within your question, you are stringifying dataSource and assinging that within state. Strings don't have the map function within JavaScript, so remove that offending code, as per below.

      return RNFS.readFile(path, 'utf8')
        .then((success) => {
          newData = JSON.parse(success);
          dataSource = newData[0].results.recordset;
          console.log("datasource "+JSON.stringify(dataSource)); 
          this.setState({
            isLoading: false,
            dataSource
          });
        })
        .catch((err) => {
          console.log(err.message);
        });