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
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.
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.
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.
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'.
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.
Related
App.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import MapboxGL from '#rnmapbox/maps';
MapboxGL.setAccessToken('TOKEN');
export default function App() {
return (
<View style={styles.page}>
<MapboxGL.MapView style={styles.map} />
<StatusBar style="auto"/>
</View>
);
}
const styles = StyleSheet.create({
page: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
map: {
flex: 1
}
});
Giving this error :
Error
Mapbox warning setAccessToken requires setWellKnownTileServer for MapLibre, see setWellKnownTileServer docs for implications Object {
"level": "warning",
"message": "setAccessToken requires setWellKnownTileServer for MapLibre, see setWellKnownTileServer docs for implications",
"tag": "InstanceManagerImpl",
And blank screen:
blank react native screen
Your map has nothing to show. Add styleJSON or styleURL option. For example (osm tiles):
const defaultStyle = {
version: 8,
name: 'Land',
sources: {
map: {
type: 'raster',
tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
minzoom: 1,
maxzoom: 19,
},
},
layers: [
{
id: 'background',
type: 'background',
paint: {
'background-color': '#f2efea',
},
},
{
id: 'map',
type: 'raster',
source: 'map',
paint: {
'raster-fade-duration': 100,
},
},
],
};
// -- map component
<MapboxGL.MapView
style={styles.map}
styleJSON={JSON.stringify(defaultStyle)}
/>
I am developing a react native app. In the app, I have a iterator mapping multiples types that are show inside a View. Each of these types have an specific color, so that is why I have an each tag for each type.
I have made a simplified example what I want and what is happening.
I want when the Text List Items exceeds its container, that they break to a new line. I tried many ways but don't discover how to do it.
The example: https://snack.expo.dev/#anschau/multiple-text-problem-not-breaking-line
The code:
import React from "react";
import { StyleSheet, Text, View } from "react-native";
const LabelTypes = [
{
styleType: "styleType1",
label: "Extensive Type 1",
},
{
styleType: "styleType2",
label: "Another Extensive Type 2",
},
{
styleType: "styleType3",
label: "Type 3",
},
{
styleType: "styleType4",
label: "Type 4",
},
{
styleType: "styleType5",
label: "Type 5",
},
{
styleType: "styleType6",
label: "Type 6",
},
];
const App = () => {
return (
<View style={[styles.container, {
flexDirection: "row"
}]}>
{
LabelTypes.map((item, index) => (
<>
{ index > 0 && <Text> - </Text>}
<Text style={[styles.label, styles[item.styleType] ]}>{item.label}</Text>
</>
))
}
</View>
);
};
const styles = StyleSheet.create({
container: {
maxWidth: "100%",
marginTop: 50,
marginLeft: 20,
marginRight: 20,
borderWidth: 1,
borderColor: "gray"
},
label: {
color: "black",
},
styleType1: {
color: "blue"
},
styleType2: {
color: "red"
},
styleType3: {
color: "green"
},
styleType4: {
color: "orange"
},
styleType5: {
color: "coral"
},
styleType6: {
color: "pink"
},
});
export default App;
Add to your container's (NOT individual labels') style:
flexWrap: 'wrap'
This will simply let items fill the container's width and fall into a new line when it doesn't fit.
I'm trying to create nested menu in react native drawer. I can create the menu as below but I have to find a way to group items and put them into accordion. This is how I currently create the menu:
import React from 'react';
import PropTypes from 'prop-types';
import { SafeAreaView, ScrollView, StyleSheet,View } from 'react-native';
import { DrawerItems,createDrawerNavigator } from 'react-navigation';
import { Container, Content, Text, List, ListItem } from "native-base";
import {Image,ImageBackground} from "react-native";
import logo from '../images/logofullwhite200.png';
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 20
}
});
const DrawerComponent = props => {
const skippedItems = Object.keys(props.drawerItems).filter(name => props.drawerItems[name].skip);
return (
<ScrollView style={styles.container}>
<SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
<Content>
<ImageBackground
source={{
uri: "https://raw.githubusercontent.com/GeekyAnts/NativeBase-KitchenSink/master/assets/drawer-cover.png"
}}
style={{
height: 120,
alignSelf: "stretch",
justifyContent: "center",
alignItems: "center"
}}>
<Image
square
style={{ height: 50, width: 150 }}
source={logo}
/>
</ImageBackground>
<DrawerItems
{...props}
onItemPress={({ focused, route }) => {
if (!skippedItems.includes(route.routeName)) {
props.onItemPress({ focused, route });
}
}}
/>
</Content>
</SafeAreaView>
</ScrollView>
);
};
DrawerComponent.propTypes = {
onItemPress: PropTypes.func,
drawerItems: PropTypes.object
};
export default DrawerComponent;
this is the data example
"CreateSale": Object {
"navigationOptions": Object {
"drawerLabel": Object {
"$$typeof": Symbol(react.element),
"_owner": null,
"_store": Object {},
"key": null,
"props": Object {
"i18nKey": "sale.create_sale",
},
"ref": null,
"type": [Function I18nextWithTranslation],
},
},
"screen": [Function KeyboardAwareNavigator],
"userInfo": Object {
"showOnLogin": true,
},
},
"Customer": Object {
"navigationOptions": Object {
"drawerLabel": Object {
"$$typeof": Symbol(react.element),
"_owner": null,
"_store": Object {},
"key": null,
"props": Object {
"i18nKey": "list.title",
},
"ref": null,
"type": [Function I18nextWithTranslation],
},
},
"screen": [Function KeyboardAwareNavigator],
"userInfo": Object {
"showOnLogin": true,
},
}
This is how index.tsx looks
export default new ClientModule({
router: <MainScreenNavigator />,
onAppCreate: [
async (modules: ClientModule) =>
(ref.navigator = createDrawerNavigator(
{
...modules.drawerItems
},
{
// eslint-disable-next-line
contentComponent: props => <DrawerComponent {...props} drawerItems={modules.drawerItems} />
}
))
]
});
I have to put the items in to accordion, they have to look nested such as as below:
Outlets
Customers
Customer
no need to make nested drawer. you can use react-native-collapsible and make custom drawerItem like accordion
yarn add react-native-collapsible
import Collapsible from 'react-native-collapsible';
() => (
<Collapsible collapsed={isCollapsed}>
<SomeCollapsedView />
</Collapsible>
);
I have an array off Object inside a variable named data.
The array looks like this:
const data = [
{
"id": "0.804802585702977",
"value": "Bar",
},
{
"id": "0.9359341974615858",
"value": "Mar",
},
{
"id": "0.4182922963461958",
"value": "Naba",
},
{
"id": "0.6132336648416628",
"value": "Socerr",
},
{
"id": "0.060587558948085984",
"value": "Mall",
},
]
I want to create a search bar to search all the value inside that array and if the search text is equal to the value inside that array the user will be able to see that value?
Please help?
You need to use filter function to search/Sort data from Array. Please check following it may solve you problem.
import React, { useState } from "react";
import { Text, TextInput, View, StyleSheet } from "react-native";
import Constants from "expo-constants";
// You can import from local files
import AssetExample from "./components/AssetExample";
// or any pure javascript modules available in npm
import { Card } from "react-native-paper";
const data = [
{
id: "0.804802585702977",
value: "Bar",
},
{
id: "0.9359341974615858",
value: "Mar",
},
{
id: "0.4182922963461958",
value: "Naba",
},
{
id: "0.6132336648416628",
value: "Socerr",
},
{
id: "0.060587558948085984",
value: "Mall",
},
];
export default function App() {
let [filteredData, setFilteredData] = useState(data);
function _searchFilterFunction(searchText, data) {
let newData = [];
if (searchText) {
newData = data.filter(function(item) {
const itemData = item.value.toUpperCase();
const textData = searchText.toUpperCase();
return itemData.includes(textData);
});
setFilteredData([...newData]);
} else {
setFilteredData([...data]);
}
}
return (
<View style={styles.container}>
<Text style={styles.paragraph}>Search Here.</Text>
<TextInput
style={styles.input}
underlineColorAndroid="transparent"
placeholder="Search"
placeholderTextColor="#9a73ef"
autoCapitalize="none"
onChangeText={(value) => {
_searchFilterFunction(value, data);
}}
/>
{filteredData.map((item, index) => {
return <Text style={styles.paragraph}>{item.value}</Text>;
})}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: "#ecf0f1",
padding: 8,
},
input: {
margin: 15,
height: 40,
paddingLeft: 10,
borderRadius: 2,
borderColor: "#7a42f4",
borderWidth: 1,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
},
});
I want to create a search bar with a drop-down list with react-native, more like this image
I know there are lots of libraries regarding these which makes my task easy but I have just started with react-native so for my knowledge I wanna know how these things are made.
I came across tutorials of how to make a search bar with live search and update the flatlist by filtering the data based on your search but none of them has a dropdown list involved.
Code updating my flatlist based on search word is already done, I need to just display this flatlist in the form of a dropdown list.
A link to tutorial or sample code would be helpful.
Check below example which i created using flatlist and TextInput. Items are displayed in the form of a dropdown list when you search items. i think this will help you.
import React, { Component } from "react";
import { View, Text, FlatList, TextInput, ListItem } from "react-native";
class FlatListDropDown extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
value: "",
};
this.arrayNew = [{ name: "Robert" }, { name: "Bryan" }, { name: "Vicente" }, { name: "Tristan" }, { name: "Marie" }, { name: "Onni" }, { name: "sophie" }, { name: "Brad" }, { name: "Samual" }, { name: "Omur" }, { name: "Ower" }, { name: "Awery" }, { name: "Ann" }, { name: "Jhone" }, { name: "z" }, { name: "bb" }, { name: "cc" }, { name: "d" }, { name: "e" }, { name: "f" }, { name: "g" }, { name: "h" }, { name: "i" }, { name: "j" }, { name: "k" }, { name: "l" }];
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE",
}}
/>
);
};
searchItems = (text) => {
const newData = this.arrayNew.filter((item) => {
const itemData = `${item.name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
data: newData,
value: text,
});
};
renderHeader = () => {
return (
<TextInput
style={{ height: 60, borderColor: "#000", borderWidth: 1 }}
placeholder=" Type Here...Key word"
onChangeText={(text) => this.searchItems(text)}
value={this.state.value}
/>
);
};
render() {
return (
<View
style={{
flex: 1,
padding: 25,
width: "98%",
alignSelf: "center",
justifyContent: "center",
}}
>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<Text style={{ padding: 10 }}>{item.name} </Text>
)}
keyExtractor={(item) => item.name}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
export default FlatListDropDown;
Feel free for doubts