Search code examples
react-nativeword-wrapreact-native-flexbox

React Native: how to combine inline elements so they get wrapped together


I have a list of comma-separated inline touchables like this:

[(<TouchableOpacity><Text>a</Text></TouchableOpacity>),
 (<Text>, </Text>),
 (<TouchableOpacity><Text>b</Text></TouchableOpacity>),
 (<Text>, </Text>),
 (<TouchableOpacity><Text>c</Text></TouchableOpacity>)]

rendering as a comma-separated string of items:

a, b, c

The problem is that sometimes comma gets wrapped to a newline, which looks kinda ugly:

a, b, c
, d

How to combine two "inline" elements so they get wrapped together?

Update. Code:

...

    let items1 = [];
    for (let i = 1; i <= 100; i++) {
        const text = makeid(i % 10 + 1);

        items1.push((<TouchableOpacity><Text style={{fontSize: 18}}>{text}</Text></TouchableOpacity>));
        items1.push((<Text style={{fontSize: 18}}>, </Text>));
    }

    return (<View style={styles.li}>
        {items1}
    </View>);

...

// just generates some random string
function makeid(len) {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < len; i++)
        text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}

const styles = StyleSheet.create({
    li: {
        width: "100%",
        flexDirection: "row",
        flexWrap: "wrap",
        marginBottom: 5,
        paddingLeft: 10
    }
});

Result:

enter image description here


Solution

  • 1. Starting solution

    According to the official documentation:

    Text supports nesting, styling, and touch handling.

    So if you're adding TouchableOpacity just to get onPress support, then it's quite useless. In that case you can simply remove it and wrap all Text blocks in a parent Text and your problem is solved.

    As you correctly note, this

    leaves a user without nice animation provided by <TouchableOpacity>.

    I thought to a better solution and it was not so far :)

    2. Other (and better?) solution

    Simply wrap your <TouchableOpacity> and related <Text> with comma in a single <View> with flexDirection: 'row' and add it to the array you're going to render.

      render() {
        let items1 = [];
        for (let i = 1; i <= 100; i++) {
          const text = makeid((i % 10) + 1);
    
          items1.push(
            <View style={{ flexDirection: 'row'}}>
              <TouchableOpacity>
                <Text style={{ fontSize: 18 }}>{text}</Text>
              </TouchableOpacity>
              <Text style={{ fontSize: 18 }}>, </Text>
            </View>
          );
        }
        return (
          <View style={styles.li}>{items1}</View>
        );
      }
    

    This way you're sure comma do not separate from its previous word and you benefit of <TouchableOpacity> animation.

    Here you can find a working example. Hope this helps!