I am studying typescript in react native.
If I typed the following code as vanilla javascript, the app works well.
But typed as a typescript, I received a message circleStyles.push(styles.circleCorrect); is an error. I understand it seems like the problem of type but I do not get how to solve it.
Does anyone have an idea?
import React from "react";
import { View, StyleSheet, Dimensions, Image } from "react-native";
const screen = Dimensions.get("window");
const styles = StyleSheet.create({
container: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
flex: 1,
alignItems: "center",
justifyContent: "center"
},
circle: {
backgroundColor: "#ff4136",
width: screen.width / 2,
height: screen.width / 2,
borderRadius: screen.width / 2,
alignItems: "center",
justifyContent: "center"
},
circleCorrect: {
backgroundColor: "#28A125"
},
icon: {
width: screen.width / 3
}
});
export const Alert = ({ correct, visible }) => {
if (!visible) return null;
const icon = correct
? require("../assets/check.png")
: require("../assets/close.png");
const circleStyles = [styles.circle];
if (correct) {
**circleStyles.push(styles.circleCorrect);**
}
return (
<View style={styles.container}>
<View style={circleStyles}>
<Image source={icon} style={styles.icon} resizeMode="contain" />
</View>
</View>
)
}
This is because TypeScript uses inference to implicitly determine types so circleStyles type is evaluated as an array of objects having the same fields than styles.circle.
You can declare circleStyles as an array of any kind of value.
const circleStyles: any[] = [styles.circle];
I would advice you however to type it more precisely by creating an interface with optional fields or using union types....
Related
I am currently working on a react native component. I want to assign the height of an image to a specific value that is calulated dynamically with the screen width. I am storing the value in a variable aspectHeight. I want to assign that value to the height in the stylesheet that I am currently calling. It is giving me the issue that the variable can not be found and I do not know how to solve this issue. I checked and I couldnt find any type of solution for this issue.
Here is my component;
import React from 'react'
import { Dimensions } from 'react-native'
import { View, Text, StyleSheet, Image } from 'react-native'
export default function PropertyTile() {
let deviceWidth = Dimensions.get('window').width - 16
var aspectHeight = (deviceWidth / 1.78) + 1
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image style={styles.mainImage} source={require('../../assets/luxury-home-1.jpeg')}/>
</View>
<View className='content-container'>
<Text>asdfas Tile</Text>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
height: '100%',
padding: 8
},
imageContainer: {
height: aspectHeight,
width: '100%',
backgroundColor: 'skyblue'
},
mainImage: {
width: '100%',
height: '100%'
}
})
Replace it with this;
import React from 'react'
import { View, Text, StyleSheet, Image, Dimensions } from 'react-native'
export default function PropertyTile() {
let deviceWidth = Dimensions.get('window').width - 16
var aspectHeight = (deviceWidth / 1.78) + 1
return (
<View style={styles.container}>
<View style={[styles.imageContainer,{height: aspectHeight}]}>
<Image style={styles.mainImage} source={require('../../assets/luxury-home-1.jpeg')}/>
</View>
<View className='content-container'>
<Text>asdfas Tile</Text>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
height: '100%',
padding: 8
},
imageContainer: {
width: '100%',
backgroundColor: 'skyblue'
},
mainImage: {
width: '100%',
height: '100%'
}
})
Nice day, good sir
I want to do something like this in react-native
<View
style = { width: '100%', padding: 10, borderRadius: '25%' }>
{...}
</View>
But I get (on iOS)
JSON value '25%' of type NSString cannot be converted to NSNumber
Is there a way to use relative/percentage values as styling input for borderRadius?
You can do something like that, use ref in order to have a reference to that element, then you can measure its width (not in percentage) and you can calculate the border radius.
import React, { useRef, useEffect, useState } from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
const ref = useRef();
const [width, setWidth] = useState(0);
useEffect(() => {
ref.current.measure((x, y, w, h) => {
setWidth(w);
});
}, []);
return (
<View style={styles.container}>
<View
ref={ref}
style={{
width: '80%',
padding: 10,
backgroundColor: 'red',
borderRadius: width / 4, // 25%
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Okay, after a quick researching, i found that borderRadius style expects number as a value, not a String
So if you want to custom the value of borderRadius, you can do sth like this:
<View style={{
width: 300,
height: 300,
backgroundColor: 'red',
padding: 10,
borderRadius: 300/4 // equal 25% of its size
}}>
I have this code and it works fine to shows the overlay the requested page for 5sec and Hide to shows the requested page's contents, But when the Loader indicator disappeared its (red) background still there, how to hide the background too?
It has two part firsts one for creating Loading Indicator to be hidden after 5 sec.
Working example on Expo.io:
Live Demo -
This is requested page's code: (Please, notice has to be called from /screens)
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Loader from './screens/Loader';
export default function App() {
return (
<View style={styles.container}>
<Loader /> //<--- I put the Loader here
<Text style={styles.paragraph}>
This is the requested page should be be covered by indicator background (Red color) <br/ >
The Loader disappear after 5 sec.<br />
But, its background still there!!
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
And the Loader.js code is :
import React, { Component } from 'react';
import { ActivityIndicator, View, Text, TouchableOpacity, StyleSheet } from 'react-native';
class Loader extends Component {
state = { animating: true }
closeActivityIndicator = () => setTimeout(() => this.setState({
animating: false }), 5000)
componentDidMount = () => this.closeActivityIndicator()
render() {
const animating = this.state.animating
return (
<View style = {styles.container}>
<ActivityIndicator
animating = {animating}
color = '#bc2b78'
size = "large"
style = {styles.activityIndicator}/>
</View>
)
}
}
export default Loader
const styles = StyleSheet.create ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 0,
position: 'absolute',
height: "100%",
width: "100%",
backgroundColor: 'red',
opacity: 0.7
},
activityIndicator: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
The problem is you are always rendering the Loader and its always visible, so the easiest way to handle this would be to return null and hide the loader when its not necessary like below.
render() {
const animating = this.state.animating;
if(!this.state.animating)
return null;
return (
<View style = {styles.container}>
<ActivityIndicator
animating = {animating}
color = '#bc2b78'
size = "large"
style = {styles.activityIndicator}/>
</View>
)
}
I am a beginner on React Native and was working on an app that fetches text and images from my API and displays it on the screen. The text is displayed but the image is not displayed. No errors. I have only one main file : App.js with the API call being
https://www.teanewsnetwork.com/api/fetcharticles.php?code=Me*z6Pcw9e1$CQ)YWgMlFe%nv(Hq)lhw&starting=0&limit=20
App.js :
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React, { Component } from 'react';
import {
View,
Text,
ActivityIndicator,
ScrollView,
StyleSheet,
Image,
} from 'react-native';
import Img from 'react-image';
let li = 'https://www.teanewsnetwork.com/profileicons/';
let bean = 'azure.jpg';
export default class App extends Component {
state = {
loading: true,
error: false,
posts: [],
};
componentWillMount = async () => {
try {
const response = await fetch(
'https://www.teanewsnetwork.com/api/fetcharticles.php?code=Me*z6Pcw9e1$CQ)YWgMlFe%nv(Hq)lhw&starting=0&limit=40'
);
const posts = await response.json();
this.setState({ loading: false, posts });
} catch (e) {
this.setState({ loading: false, error: true });
}
};
renderPost = ({ id, title, content, authorimage, authorname }, i) => {
let b = { authorname };
return (
<View style={styles.postContent}>
<Text>{authorname}</Text>
<Image
source={{
uri: 'https://teanewsnetwork.com/profileicons/',
}}
style={{ width: 40, height: 40 }}
/>
<Text style={styles.postauthor}>{title}</Text>
<Text style={styles.postBody}>{content}</Text>
</View>
);
};
render() {
const { posts, loading, error } = this.state;
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator animating={true} />
</View>
);
}
if (error) {
return (
<View style={styles.center}>
<Text>Failed to load posts!</Text>
</View>
);
}
return (
<ScrollView style={styles.container}>
{posts.map(this.renderPost)}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
postauthor: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#EEE',
paddingVertical: 25,
paddingRight: 15,
},
postContent: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#EEE',
paddingVertical: 25,
paddingRight: 15,
left: 10,
},
postBody: {
marginTop: 10,
fontSize: 12,
color: 'lightgray',
left: 10,
},
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
I want to display my images below every name which are to be taken from the link
www.teanewsnetwork.com/profileicons/{{authorimage}}
Where {{authorimage}} is given in the API. But this doesn't seem to work.
Thanks is advance!
You can use template literals in JavaScript. This will append the authtorimage to the end of the string.
<Image
source={{
uri: `https://teanewsnetwork.com/profileicons/${authorimage}`,
}}
style={{ width: 40, height: 40 }}/>
Template literals are enclosed by the back-tick (```) (grave accent) character instead of double or single quotes. Template literals can contain placeholders. These are indicated by the dollar sign and curly braces (${expression}). The expressions in the placeholders and the text between them get passed to a function.
You are doing it very correctly except in two places which I have pointed below:
- While importing the react native components you are also doing:
import Img from 'react-image';
This is unnecessary as react native itself provides Image components.
- Also, you need to pass value of authorimage in source of the image as:
<Image
source= {{
uri: `https://teanewsnetwork.com/profileicons/${authorimage}`,
}}
style={{height: 40, width: 40}}
/>
Here, is the link of working snack.
If you want to learn more about how images works in react native, you can visit this link.
I currently have an auto-growing text input field that will expand to a certain clamped height.
The issue is that once the text input has grown to its max size, the content that I write gets pushed under the container. See attached images
Before Issue:
Expanded view, before issue
Post Issue:
Cursor has disappeared from view
I though about having the Text Input scroll to the end, but I haven't found any documentation or API that allows me to scrollTo end of the input. (Similar to ScrollView)
The final functionality is that of a chat application messaging box.
Code:
import React, { Component } from 'react';
import { View, TextInput } from 'react-native';
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
class AutogrowTextInput extends Component {
constructor(props) {
super(props);
this.state = {'contentHeight': props.minHeight};
this.resize = this.resize.bind(this);
}
render() {
let height = clamp(this.state.contentHeight, this.props.minHeight, this.props.maxHeight) + 20;
let inputStyle = {height: height, flex: 0};
return (
<TextInput
{...this.props}
style={[this.props.style, inputStyle]}
onContentSizeChange={this.resize}
underlineColorAndroid="transparent"
/>
);
}
resize(event) {
this.setState({
'contentHeight': event.nativeEvent.contentSize.height,
});
}
}
export default AutogrowTextInput;
Instantiation of Element.
return (
<View style={style.footer}>
<TouchableIcon
onPress={this._attach}
icon="add"
color="#000"
/>
<AutogrowTextInput
underlineColorAndroid="transparent"
style={style.input}
placeholder="Send Message"
value={message}
onChangeText={this._changeText}
autoFocus={false}
multiline={true}
minHeight={30}
maxHeight={100}
/>
{attachmentComps}
<TouchableIcon
disabled={sending || isEmpty}
onPress={this._sendMessage}
icon="send"
color="#000"
/>
</View>
);
Styling:
footer: {
borderTopWidth: StyleSheet.hairlineWidth,
borderColor: '#ccc',
paddingVertical: 4,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 10,
backgroundColor: '#fff',
flex: 0
},
input: {flexGrow: 1, fontSize: 16, paddingHorizontal: 10, paddingVertical: 1},
attachmentContainer: {marginHorizontal: 4},
attachment: {height: 40, width: 40, borderRadius: 2},
Thanks in advance.
P.S. Cannot post images in line because of lack of reputation.