10

I am trying to toggle a Modal in react native. Each item in a flatlist should have a toggle option to open a modal.

I get the error: JSX expressions must have one parent element.

I have tried to google for the right syntax but can't find a solution.

class CategoriesScreen extends Component {

  state = {
    modalVisible: false,
  };

  setModalVisible(visible) {
    this.setState({ modalVisible: visible });
  }

  render() {
function Item({ title }) {
      return (
        <TouchableOpacity style={styles.item} onPress={() => {
          this.setModalVisible(true);
        }}>
          <View>
            <Text style={styles.title}>{title}</Text>
          </View>
        </TouchableOpacity> 
        <Modal
          animationType="slide"
          transparent={false}
          visible={this.state.modalVisible}
          onRequestClose={() => {
            Alert.alert('Modal has been closed.');
          }}>
          <View style={{ marginTop: 22 }}>
            <View>
              <Text>Hello World!</Text>

              <TouchableOpacity
                onPress={() => {
                  this.setModalVisible(!this.state.modalVisible);
                }}>
                <Text>Hide Modal</Text>
              </TouchableOpacity>
            </View>
          </View>
        </Modal>
    };
    return (
      <SafeAreaView style={styles.container}>
        <Text style={styles.heading}>Select a category for daily tasks.</Text>
        <Text style={styles.subheading}>{`You will receive a daily task in this category.\nLet’s get consistent!`}</Text>
        <FlatList
          data={DATA}
          renderItem={({ item }) => <Item title={item.title} />}
          keyExtractor={item => item.id}
          numColumns={2}
        />
      </SafeAreaView>
    );
  }
}

I am trying to get open one unique modal for each item in the flatlist.

9minday
  • 343
  • 4
  • 6
  • 21
  • If you are looking for unique modals, then I would just having unique state variables for managing each of them. You can't manage all the modals with a common state variable. You can have an attribute inside a flatlist object which manages the state of the modal. – Senthil Kumar Oct 20 '19 at 22:48

1 Answers1

17

You can only return a single entity. To fix this just surround your return in your Item function with a <Fragment/> element (from the react package).

Fragments let you group a list of children without adding extra nodes to the DOM.

This can be done like so:

import React, {Fragment} from 'react';
... 
function Item({ title }) {
    return (
      <Fragment>
        <TouchableOpacity style={styles.item} onPress={() => {
          this.setModalVisible(true);
        }}>
          <View>
            <Text style={styles.title}>{title}</Text>
          </View>
        </TouchableOpacity> 
        <Modal
          animationType="slide"
          transparent={false}
          visible={this.state.modalVisible}
          onRequestClose={() => {
            Alert.alert('Modal has been closed.');
          }}>
          <View style={{ marginTop: 22 }}>
            <View>
              <Text>Hello World!</Text>

              <TouchableOpacity
                onPress={() => {
                  this.setModalVisible(!this.state.modalVisible);
                }}>
                <Text>Hide Modal</Text>
              </TouchableOpacity>
            </View>
          </View>
        </Modal>
      </Fragment>
   )
};

Hope this helps,

Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
  • 3
    You can also use the shorthand `<>>` as well. – woat Oct 20 '19 at 22:52
  • @woat I believe you need a babel plugin for that still, no? – Miroslav Glamuzina Oct 20 '19 at 22:52
  • This fixed the error but instead I get this error now: TypeError: TypeError: undefined is not an object (evaluating 'this.state.modalVisible') – 9minday Oct 20 '19 at 23:00
  • 1
    Ahh I see. I believe you need a constructor. and set your state object inside of it instead of were it currently is like so: `constructor(props){ super(props); this.state = { modalVisible: false, }; }` – Miroslav Glamuzina Oct 20 '19 at 23:03
  • @MiroslavGlamuzina Thank you :) I am trying, not sure where to put it? – 9minday Oct 20 '19 at 23:06
  • No problem. It will go right underneath this line -> `class CategoriesScreen extends Component {`. (don't forget to remove `state = {modalVisible: false};` (this will be in the constructor like the snippet I last sent) – Miroslav Glamuzina Oct 20 '19 at 23:11
  • 1
    Great! I added it like this. ```react-native class CategoriesScreen extends Component { constructor(props){ super(props); this.state = { modalVisible: false, }; } ``` I still have the problem: undefined is not an object (evaluating 'this.state.modalVisible') – 9minday Oct 20 '19 at 23:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201176/discussion-between-9minday-and-miroslav-glamuzina). – 9minday Oct 20 '19 at 23:21