I have multiple functions that looks almost identical. How can I refactor my function so that I don't have write multiple functions.
This is my code:
renderImage = () => {
var imgSource = this.state.image? imageOne : imageTwo;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
source={ imgSource }
/>
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>some text</Text>
</View>
);
}
I have another function that looks very similar:
renderImage2 = () => {
var imgSource = this.state.image2? imageThree : imageFour;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
//I want to change source
source={ imgSource }
/>
//Also I want to change text
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>some other text</Text>
</View>
);
}
I just want to change the Image source and the text. Can I do this?
Create another component that returns the render but takes 2 props you pass in (source, text)
import React from 'react';
import { Image, Text, View } from 'react-native';
class ImageWithText extends React.PureComponent {
render() {
const { source, text } = this.props;
return (
<View style={{ marginLeft: 20, marginTop: 20, width: 50, height: 67, backgroundColor: 'transparent', alignItems: 'center' }}>
<Image style={{ width: 46, height: 46 }} source={source} />
<Text style={{ paddingTop: 4, fontSize: 11, color: '#4a4a4a' }}>{text}</Text>
</View>
);
}
}
export default ImageWithText;
and when you want to use the new component
renderImage = () => {
var imgSource = this.state.image? imageOne : imageTwo;
return (
<ImageWithText source={imgSource} text="some text">
);
}
You can first define a renderImage function that takes in a parameter to do decision making. Within this renderImage function, define all the possible images to load within a lookup object, such as below
renderImage = (renderImage) => {
const lookup = {
image_1: { src: imageOne, text: 'text_for_image_one' },
image_2: { src: imageTwo, text: 'text_for_image_two' }
}
const selectedImage = lookup[renderImage] || undefined;
if(!selectedImage) return;
return (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
source={selectedImage.src}
/>
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>{selectedImage.text}</Text>
</View>
);
}
Then within your render method do below
render() {
...
{this.renderImage(image_1)}
{this.renderImage(image_2)}
...
}
You can define simple function render like
renderImage = (imageSrc, text) => (
<View style={{marginLeft:20, marginTop:20,width:50, height:67, backgroundColor:'transparent', alignItems:'center'}}>
<Image
style={{width:46, height:46}}
//I want to change source
source={ imageSrc }
/>
//Also I want to change text
<Text style={{paddingTop:4, fontSize:11, color:'#4a4a4a'}}>{text}</Text>
</View>
)
end use in your render like:
{this.renderImage(this.state.image? imageOne : imageTwo, 'some text')}
Related
Can anyone tell me how to solve these things?
1.if the list is pressed, I'd like to change the background color of the list
beige(#FFF5E7) to white(#FBFBFB)
2.Also, I'd like to change the read value of the Object fales to true with useState
Problem is that if I pressed the list, whole background color of the list will be changed.
index.tsx
import React, { useState } from 'react';
import { Text, View, TouchableOpacity, FlatList } from 'react-native';
import { useNavigation } from '#react-navigation/native';
import { DETAIL } from '../../sample';
import { Object } from './sample';
export default function sample() {
const [state, setState] = useState(Object);
const navigation = useNavigation();
let Element;
const renderItem = ({ item }) => {
const readState = () => {
navigation.navigate(NOTICE_DETAIL);
const readValue = [...state];
let value = { ...readValue[0] };
value.read = true;
readValue[0] = value;
setState(readValue);
};
if (state[0].read) {
Element = (
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: '#FBFBFB' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
);
} else {
Element = (
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: '#FFF5E7' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
);
}
return Element;
};
}
return (
<View style={{ flex: 1 }}>
<FlatList
extraData={Object}
data={Object}
renderItem={renderItem}
/>
</View>
);
}
Object.ts
export const Object = [
{
id: 1,
text: 'testtesttest',
content: 'testtesttest'
read: false
},
{
id: 2,
text: 'testtesttest',
content: 'testtesttest'
read: false
}
id: 3,
text: 'testtesttest',
content: 'testtesttest'
read: false
}
]
We can add inline styles into the component style props along with static styles,
For Example:
<TouchableOpacity onPress={readState}>
<View style={[styles.row, { backgroundColor: item.read ? '#FBFBFB' : 'FFF5E7' }]}>
<View style={styles.container}>
<View style={styles.end}>
<Text style={styles.text}>{item.text}</Text>
<Text style={styles.time}>{item.time}</Text>
</View>
<Text style={styles.content}>{item.content}</Text>
</View>
</View>
</TouchableOpacity>
Problem in your readState function and if (state[0].read) {. You always change item with index 0 and then check state[0].read for all elements of your array.
I have this SMN() function and I've created inside it Site function as Const. So I need to call Site function in Render() function. This is main function code:
SMN() {
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }} style={{ marginTop: 20 }} />
</View>
);
}
});
This is Render() function where I want to call Site function from it, I've used:
this.SMN().Site , this does not throw errors but does not display any.
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}
Make your Site as a component just like this:
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView
source={{ uri: 'https://www.google.com' }}
style={{ marginTop: 20 }} />
</View>
);
}
And in your render function use it like this:
render() {
return (
</View>
<View><Site /></View>
</View>
)
}
I think you want to get the return you want from SMN(). So this is what I thought your intended solution was.
SMN() {
return (
{
Site : () => (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }}
style={{marginTop:20 }} />
</View>
)
}
);
});
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}
<View style={styles.card} >
{store.crud.list.map(function(element, index){
return (
<View style={styles.wrapper}>
{element.map(function(number, index){
return(
<View>
<Text style={styles.number}>
{element}
</Text>
</View>
);
})}
</View>
);
})}
</View>
I have this react-native element and it seems that it won't render, the second render seems to break the code, because I remove it and just render element, it works fine.
I am getting the error:
TypeError: "Text constructor: 'new' is required"
React 12
unstable_runWithPriority scheduler.development.js:643
React 6
Also, the content of store.crud is { list: [[2,3,3,3,3,4],[3,1,1,1,1,1]] }. It's simple number refers to the number and element refers to the array.
The following works fine:
<View style={styles.card} >
{store.crud.list.map(function(element, index){
return (
<View style={styles.wrapper}>
{element}
</View>
);
})}
</View>
However, as I've said, I want to style every number inside element.
EDIT: I also tried this and it doesn't work even though it works on Codesandbox:
const ConfigScreen = () => {
let store = {
crud:{
list:[[1,2,3,4,5,6],[1,23,45,65,8]]
}
};
return (
<View style={styles.card} >
{store.crud.list.map(function (element, index) {
return (
<View style={styles.wrapper}>
{element.map(function (number, index) {
return (
<View>
<Text style={styles.number}>
{number}
</Text>
</View>
);
})}
</View>
);
})}
</View>
);
};
Is it an issue with the expo client/metro bundler?
I entered expo start --no-https and then clicked on "Run in web browser".
Try this
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
class App extends Component {
store = {
crud:{
list:[[1,2,3,4,5,6],[1,23,45,65,8]]
}
};
render() {
return (
<View style={styles.card} >
{this.store.crud.list.map(function (element, index) {
return (
<View style={styles.wrapper}>
{element.map(function (number, index) {
return (
<View>
<Text style={styles.number}>
{number}
</Text>
</View>
);
})}
</View>
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500
},
logo: {
height: 80
},
header: {
padding: 20
},
title: {
fontWeight: "bold",
fontSize: "1.5rem",
marginVertical: "1em",
textAlign: "center"
},
text: {
lineHeight: "1.5em",
fontSize: "1.125rem",
marginVertical: "1em",
textAlign: "center"
},
link: {
color: "#1B95E0"
},
code: {
fontFamily: "monospace, monospace"
}
});
export default App;
This code works as . Also, you can try to run this code on this site https://codesandbox.io/s/q4qymyp2l6?file=/src/App.js
Try to use flat list, see expo example - https://docs.expo.io/versions/latest/react-native/flatlist/
How do I map over two different arrays in react native? In my case I'm fetching a response from server and mapping over it. Also there is another array named images which I want to list along with the fetched response from server.But the second mapping is looping within the first one. How do I separate it from the first?Following is my code.
sample code
<ScrollView>
{this.state.workers.map(a =>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog.show()}>
<View style={{ marginTop: 10, marginLeft:120}}>
{images.map(b =>
<Image
style={{ height: 100, width: 100 }}
source={{ uri: b.image }}
/>
)}
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
)}
workers array is the json response I'm fetching from server.images array is as folows
export const images = [
{
image:'http://localhost:3000/Images/carpenter.png',
text:'hello'
},
{
image:'http://localhost:3000/Images/electrician.png',
text:'hii'
},
]
Also this how workers array looks like
updated
[
{
"sl.no": 1,
"worker_id": "wr_1",
"work_type": "carpenter",
"phone_num": "3456789243"
},
{
"sl.no": 2,
"worker_id": "wr_2",
"work_type": "electrician",
"phone_num": "345221344"
},
{
"sl.no": 3,
"worker_id": "wr_3",
"work_type": "plumber",
"phone_num": "8976545677"
}
]
You can simply move it above the first map and save the result:
render() {
const imagesToRender = images.map(b => {
return (
<Image
style={{ height: 100, width: 100 }}
source={{ uri: b.image }}
/>
);
});
return (
<ScrollView>
{this.state.workers.map(a =>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog.show()}>
<View style={{ marginTop: 10, marginLeft:120}}>
{imagesToRender}
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
)}
</ScrollView>
);
}
Also, don't forget to add key props to each Image and each CardSection.
you can easily use flatlist with better performance
import React, { Component } from "react";
import { View, FlatList, TouchableOpacity, Image, Text } from "react-native";
const workers = [
{ id: 1, name: 'Nima', images: [{ image: 'https://www.lens-rumors.com/wp-content/uploads/2014/10/Nikon-AF-S-DX-Nikkor-18-140mm-f3.5-5.6G-ED-VR-sample-images1.jpg', text: 'hello' },{ image: 'https://www.lens-rumors.com/wp-content/uploads/2014/10/Nikon-AF-S-DX-Nikkor-18-140mm-f3.5-5.6G-ED-VR-sample-images1.jpg', text: 'hello' },{ image: 'https://www.lens-rumors.com/wp-content/uploads/2014/10/Nikon-AF-S-DX-Nikkor-18-140mm-f3.5-5.6G-ED-VR-sample-images1.jpg', text: 'hello' },{ image: 'https://www.lens-rumors.com/wp-content/uploads/2014/10/Nikon-AF-S-DX-Nikkor-18-140mm-f3.5-5.6G-ED-VR-sample-images1.jpg', text: 'hello' }] },
{ id: 2, name: 'Mike', images: [{ image: 'https://www.dike.lib.ia.us/images/sample-1.jpg/image', text: 'goodby' },{ image: 'https://www.dike.lib.ia.us/images/sample-1.jpg/image', text: 'goodby' },{ image: 'https://www.dike.lib.ia.us/images/sample-1.jpg/image', text: 'goodby' },{ image: 'https://www.dike.lib.ia.us/images/sample-1.jpg/image', text: 'goodby' },] },
]
class Test extends Component {
constructor(props) {
super(props);
this.state = {
workers: workers
};
}
_renderItem = ({ item }) => {
console.log(item);
return (
<View style={{ flex: 1 }}>
<TouchableOpacity>
<View style={{ marginTop: 10, marginLeft: 120 }}>
{item.images.map((b, index) => {
console.log(b.image);
return (
<View key={index}>
<Image
style={{ height: 100, width: 100 }}
source={{ uri: b.image }}
/>
<Text
style={{ marginLeft: 20, fontSize: 20, color: "black" }}
>
{b.text}
</Text>
</View>
);
})}
<Text style={{ marginLeft: 20, fontSize: 20, color: "black" }}>
{item.name}
</Text>
</View>
</TouchableOpacity>
</View>
);
};
_keyExtractor = (item, index) => item.id.toString();
render() {
return (
<FlatList
data={this.state.workers}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
export default Test;
If the images don't load, it's probably because you pass the wrong properties to the <Image /> component. Look up the docs for <Image /> component or replace it with <img /> instead and pass the url string of the image to the src attribute.
getImageUri(worker) {
// Decide which image to return for a certain type of worker
// For more workers and images, change the following logic
if(worker.work_type == 'carpenter') {
return images[0].image;
} else if(worker.work_type == 'electrician') {
return images[1].image;
} else {
return '';
}
}
render() {
...
<ScrollView>
{this.state.workers.map((a, index) =>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog.show()}>
<View style={{ marginTop: 10, marginLeft:120}}>
<Image
style={{ height: 100, width: 100 }}
source={{ uri: this.getImageUri(a)}}
/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
)}
</ScrollView>
...
}
I have a text component
<Text ref="text" style{...}>{this.state.te}</Text>
and I would like to insert and append other <Text></Text>
so when the event fires on a button I want it to insert a new <Text></Text> to look like this
<Text ref="text" style{...}>
<Text ref="text" style{...}>first</Text>
<Text ref="text" style{...}>second</Text>
<Text ref="text" style{...}>third</Text>
</Text>
this is what my event looks like
insertText(){
this.setState({te: this.state.te + <Text style={...}>{this.refs.newText.props.value}</Text>})
}
when I do this all it renders is "[object object]" inside of the Text Component
if I use
this.setState({te: <Text style={...}>{this.refs.newText.props.value}</Text>})
it will render the text just fine with a single <Text></Text> element.
any help would be appreciated. Thanks.
Edit:
this.state.te holds te: <Text></Text>
Ok, check out what I have below. I've essentially created an array of text values that are place in between two <Text> fields, and when the insertText function is called, it pushes a new text element to the array, then resets the state of the array to the te property:
getInitialState: function() {
return {
te: [<Text>Yo</Text>],
index:1
}
},
insertText: function() {
this.state.te.push(
<Text>Text number {this.state.index}</Text>
)
this.setState({
index: this.state.index + 1,
te: this.state.te
})
},
render: function() {
var MyText = function(t) {
return(
<Text>
{t}
</Text>
)
}
return (
<View style={styles.container}>
{MyText(this.state.te)}
<TouchableHighlight onPress={ () => this.insertText() } style={{ marginTop:20, height:60, flexDirection: 'row', backgroundColor: '#ededed', justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 22 }}>Add Text</Text>
</TouchableHighlight>
</View>
);
I've set up the full working project here. Full code is also posted below.
https://rnplay.org/apps/Itk6RQ
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight
} = React;
var SampleApp = React.createClass({
getInitialState: function() {
return {
te: [<Text>Yo</Text>],
index:1
}
},
insertText: function() {
this.state.te.push(
<Text>Text number {this.state.index}</Text>
)
this.setState({
index: this.state.index + 1,
te: this.state.te
})
},
render: function() {
var MyText = function(t) {
return(
<Text>
{t}
</Text>
)
}
return (
<View style={styles.container}>
{MyText(this.state.te)}
<TouchableHighlight onPress={ () => this.insertText() } style={{ marginTop:20, height:60, flexDirection: 'row', backgroundColor: '#ededed', justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 22 }}>Add Text</Text>
</TouchableHighlight>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 60
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);