16

Suppose I have a simple React Native app like so:

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  Text,
  TouchableHighlight,
  View,
} = React;

var ReactProject = React.createClass({
  _onPressOut: function() {
    // What do we do here?
  },

  render() {
    return (
      <View>
        <Text>This text should be before</Text>
        <Text>This text should be after</Text>
        <TouchableHighlight onPressOut={this._onPressOut}>
          <Text>Tap Me</Text>
        </TouchableHighlight>
      </View>
    );
  }
});

AppRegistry.registerComponent('ReactProject', () => ReactProject);

How can I dynamically insert a component between the first and second Text tags when the TouchableHighlight is pressed?

2
  • 3
    React philosophy is, State -> UI and hence change state/props to change ui and not mutating ui elements directly. Commented Feb 19, 2016 at 14:29
  • React-native is compiled code, so you can't do real dynamic. Commented Mar 13, 2021 at 20:19

4 Answers 4

27

Try creating an array and attaching it to the state. You can then push items to the array, and reset the state.

https://rnplay.org/apps/ymjNxQ

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight
} = React;

var index = 0

var SampleApp = React.createClass({

  getInitialState(){
    return { myArr: [] }
  },

  _onPressOut() {
    let temp = index ++
    this.state.myArr.push(temp)
    this.setState({
        myArr: this.state.myArr
    })
  },

  render() {

    let Arr = this.state.myArr.map((a, i) => {
      return <View key={i} style={{ height:40, borderBottomWidth:2, borderBottomColor: '#ededed' }}><Text>{ a }</Text></View>                            
    })    
    return (
      <View style={styles.container}>
        <Text>First</Text>
        { Arr }
        <Text>Second</Text>
        <TouchableHighlight style={ styles.button } onPress={ () => this._onPressOut() }>
            <Text>Push</Text>
        </TouchableHighlight>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop:60
  },
  button: {
    height:60,
    backgroundColor: '#ededed',
    marginTop:10,
    justifyContent: 'center',
    alignItems: 'center'
  }
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);

I've set up a working example here.

Sign up to request clarification or add additional context in comments.

4 Comments

I understand what you did there, but it's not exactly what I'm looking to accomplish. It's not about showing and hiding a component, I need to be able to add components. Press once, you get one new component. Press again and you get a second, and so on.
Sorry about the misunderstanding, I've updated both the example and my code.
This is getting much closer to what I had in mind, thanks. It's still troubling that you can't arbitrarily select the insertion point by passing a reference to the element before or after it (or perhaps the container), but this is at least a viable starting point.
my mistake was that i just pushed to the state. what causes the render is calling setState()
4

In react or react native the way component hide/show or add/remove does not work like in android or iOS. Most of us think there would be the similar stratedgy like

View.hide = true or parentView.addSubView(childView

But the way react native work is completely different. The only way to acheive this kind of functionality is to include your component in your DOM or remove from DOM.

Here in this example I am going set the visibility of text view based on the button click. enter image description here

enter image description here

The idea behind this task is the create a state variable called state having the initial value set to false when the button click event happens then it value toggles. Now we will use this state variable during the creation of component.

import renderIf from './renderIf'

class fetchsample extends Component {
  constructor(){
    super();
    this.state ={
      status:false
    }
  }
  toggleStatus(){

  this.setState({
    status:!this.state.status
  });
  console.log('toggle button handler: '+ this.state.status);
  }

  render() {
    return (
      <View style={styles.container}>
       {renderIf(this.state.status)(
         <Text style={styles.welcome}>
         I am dynamic text View
         </Text>
       )}

        <TouchableHighlight onPress={()=>this.toggleStatus()}>
          <Text> touchme </Text>
        </TouchableHighlight>
      </View>
    );
  }
}

the only one thing to notice in this snippet is renderIf which is actually a function which will return the component passed to it based on the boolean value passed to it.

renderIf(predicate)(element).

renderif.js

'use strict';
const isFunction = input => typeof input === 'function';
export default predicate => elemOrThunk =>
  predicate ? (isFunction(elemOrThunk) ? elemOrThunk() : elemOrThunk) : null;

Comments

3

With React components you don't want to think of actions reaching into the DOM and inserting components - you want to think components responding to actions. Theoretically, this component is already composed and ready, it just needs to know if it should be rendered or not:

var ReactProject = React.createClass({
  getInitialState() {
    // our *state* dictates what the component renders
    return {
      show: false
    };
  }
  _onPressOut: function() {
    // update our state to indicate our "maybe" element show be shown
    this.setState({show: !this.state.show});
  },
  maybeRenderElement() {
    if (this.state.show) {
      // depending on our state, our conditional component may be part of the tree
      return (
        <Text>Yay!</Text>
      );
    }
    return null;
  }
  render() {
    return (
      <View>
        <Text>This text should be before</Text>
        {this.maybeRenderElement()}
        <Text>This text should be after</Text>
        <TouchableHighlight onPressOut={this._onPressOut}>
          <Text>Tap Me</Text>
        </TouchableHighlight>
      </View>
    );
  }
});

I've also made a helper that makes it easy to conditionally render things, render-if

renderIf(this.state.show)(
  <Text>Yay</Text>
)

1 Comment

My issue is more about being dynamic rather than show and hide. If the user presses that button twice, I need to insert 2 more elements. If they push it 10 times, I need to add 10. Ultimately there may be a delete button as well. It's all about being able to dynamically add or remove elements from on screen.
3

ECMA6 Syntax

import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,    
TextInput,
TouchableOpacity,
TouchableHighlight
} from 'react-native';    

export default class fourD extends Component {

  constructor(props) {
    super(props);
    let ele1 = (
      <View key={1}>
        <Text>Element {1}</Text>
        <TouchableOpacity onPress={ () => this._add()  }>
         <Text>Add</Text>
        </TouchableOpacity>
      </View>
     );

    this.state = {
      ele: [],
      key: 1
    }

    this.state.ele.push(ele1);

   }

  _add(){

    let key = this.state.key + 1;

    let ele2 = (
      <View key={key}>
        <Text>Element {key}</Text>
        <TouchableOpacity onPress={ () => this._add()  }>
         <Text>Add</Text>
        </TouchableOpacity>
      </View>
    );

    let ele = this.state.ele;
    ele.push(ele2);
    this.setState({ ele: ele,key : key})

  }
  render() {

    return (
      <View style={styles.container}>
       <Text>This text should be before</Text>
        { this.state.ele }
       <Text>This text should be after</Text>
       <TouchableHighlight onPressOut={ () => this._add()  }>
          <Text>Tap Me</Text>
        </TouchableHighlight>
      </View>
    )
  }
}



const styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "white",
    }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.