20

Is it possible to dynamically create and add view components in React Native? For example, firstly I have only empty screen and information of all views come from server in JSON, and then it is need to generate them on the screen. For example - application getting json from server. This json describes the screen that have to be builded:

{
    "type": "linearlayout",
    "subviews": [{
        "type": "text",
        "fields": {
            "text": "This is text field"
        },
        "styles": {
            "color": "",
            "textSize": 14
        }
    }, {
        "type": "button",
        "fields": {
            "text": "JUST BUTTON"
        },
        "transition": {
            "name": "http://www.link.com"
        }
    }, {
        "type": "text",
        "fields": {
            "text": "This is another text field"
        },
        "styles": {
            "color": "",
            "textSize": 18
        }
    }]
}

So, by that JSON I need dynamically views building in React Native. But I can't see any ability to write JS code inside JSX - only static views and dynamically changing of props

1
  • 1
    Did you end up finding a solution for this? I'm also looking for something similar. Commented Sep 7, 2017 at 16:22

5 Answers 5

16

Yes this is possible. Assume that you retrieve your JSON data successfully and save it to some state then in your render function you can use it like that;

render() {
    var productList = [];

        this.state.data.products.forEach(function (tmpProduct) {
            productList.push(
                <View style={cardView} key={tmpProduct.id}>

                    <Grid style={upperGrid}>
                        <Col style={{flex: 0.5}}>
                            <Thumbnail
                                source={require('../../../images/sample-image.png')}
                                style={itemThumb}>
                        </Col>
                        <Col>
                            <Text style={cardItemHeader} numberOfLines={2}>{tmpProduct.title}</Text>
                            <Text style={cardItemBody} numberOfLines={2}>{tmpProduct.description}</Text>
                        </Col>
                    </Grid>
                </View>
            );
        }.bind(this));

    return (
        <Container theme={theme}>
            <Image source={require('../../../images/grad-bg.png')} style={background} >

                <Content style={scrollContent}>

                    {productList}

                </Content>

            </Image>
        </Container>
    )
}

I hope this code piece give you an idea. You can adapt it to your case.

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

5 Comments

Thank you for example. But my need is not same - you are setting properties for already created views. Before starting app you know what views will be created, and you describe them in code (Image, Text, Container...). But in my case - I don't know what views will be created, because all information about types (is it Text or Image, or Button) will come from server after application load.
I see, but even in your case you should better predefine components and then selectively use them in your render function. You can read this and this for more.
May I ask sir why did you specify the key for each product view?
Is it for getting product id for item selected?
@0x01Brain You better read this. Basically key prop is used to differentiate simple anonymous components in arrays while rendering these arrays as lists.
7

React docs (and by extension it could be done with ReactNative too) show how to choose the component type at runtime:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

Doing so, you could just only need to walk on your JSON tree and just create the ReactNative components, using the components object as a mapping between the type defined in the JSON tree and their constructors.

Comments

4

Here is another approach:-

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';


const renderObject = {
  type : "View",
  children : [
    {
      type: "View",
      styles: {
        backgroundColor: "orange",
        flex:1,
        justifyContent:"center",
        alignItems: "center"
      },
      children: [
        {
          type: "Text",
          styles: {
            color: "yellow",
            fontSize: 20
          },
          text: "Hello"
        },
        {
          type: "View",
          styles: {
            backgroundColor: "red",
            width: 100,
            height: 5,
            marginTop: 10
          },
          children: []
        }
      ]
    },
    {
      type: "View",
      styles: {
        flex:1,
        justifyContent:"center",
        alignItems: "center"
      },
      children: [
        {
          type: "Text",
          styles: {
            color: "red",
            fontSize: 40
          },
          text: "Hello"
        }
      ]
    },
    {
      type: "View",
      styles: {
        flex:1,
        justifyContent:"center",
        alignItems: "center",
        backgroundColor: "green"
      },
      children: [
        {
          type: "Text",
          styles: {
            color: "white",
            fontSize: 80
          },
          text: "Hello"
        }
      ]
    }
  ],
  styles: {
    flex:1
  }
}

const CustomComp = (props) => {
  const {type} = props;
  if(type == "View"){
    const {styles, children} = props;
    return <View style={styles}>{children.map((item) => CustomComp(item))}</View>
  } else if(type == "Text") {
    const {styles, text} = props;
    return <Text style={styles} >{text}</Text>
  }
}

export default function App() {
  return (
    <View style={styles.container}>
      {CustomComp(renderObject)}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent: 'center',
  },
});

You can find the full code on this Repo.

Comments

1

Yes it is possible to dynamically create components in React Native based on data you retrieve from the server.

However, if you are wanting the app to check for the latest JS code (including new components/views) without requiring an update through app store, you could use something like code-push. https://microsoft.github.io/code-push/

Your question is somewhat vague so if I misunderstood then possibly you could give an example 'information of all views'.

1 Comment

I've added some descriptions about my question
-1

One of the benefits of using react native (vs webview) is that your users won't be staring at empty screens when the app is loading data. If you return all views from server, then it works like web page. I have done something like that before. Believe me that's not the best UX. Ideally json response should only return data. Then client can be built with any framework (react native, iOS or Android native) and they share the same API endpoints.

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.