I am starting to learn sliders and other basic components in react native. I would like to print the current value of the slider in the terminal. I tried putting console.log() in different places, but didn't know what I was doing and got errors.
import React, { Component } from 'react';
import { Slider, View, Text } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
sliderValue: "0",
};
}
render() {
return (
<View
style={{
flex: 1,
padding: 20,
justifyContent: "center",
backgroundColor: "#ecf0f1",
}}>
<Text style = {{ color: "black" }}>
Value of this slider is : {this.state.sliderValue}
</Text>
<Slider
maximumValue = {10}
minimumValue = {0}
step = {1}
value = {this.state.sliderValue}
onValueChange = {sliderValue => this.setState({ sliderValue })}
/>
</View>
);
}
}
Well, you have many options here, I'll give you 2.
You can just console log in your render method
render() {
console.log(this.state.sliderValue);
//the reset of your code
}
Or you can do it inline with the setState call
onValueChange = {sliderValue => console.log(sliderValue) || this.setState({ sliderValue })}
Related
I am a bit new to react native and I have an issue I need help with
how do I build a text input in react native that has a placeholder that changes to a text view on top when clicked?
Similar to the screenshot below
empty text input field looks like this in its default state
text field with data entered
see the empty input text has a placeholder appearing in the middle of the input text field
see the second diagram, the place holder text is moved to the top of the input field once the user starts typing text into the input field
The easiest way is to use react-native-paper package with their text input:
import * as React from 'react';
import { TextInput } from 'react-native-paper';
const MyComponent = () => {
const [text, setText] = React.useState('');
return (
<TextInput
label="Email"
value={text}
onChangeText={text => setText(text)}
/>
);
};
export default MyComponent;
Result:
Here is what I use without any library, working example and if you want to add animation to the fields working example with animation
import React, { Component } from 'react';
import {
View,
StatusBar,
TextInput,
Text,
} from 'react-native';
class FloatingLabelInput extends Component {
state = {
isFocused: false,
};
handleFocus = () => this.setState({ isFocused: true });
handleBlur = () => this.setState({ isFocused: false });
render() {
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 18 : 0,
fontSize: !isFocused ? 20 : 14,
color: !isFocused ? '#aaa' : '#000',
};
return (
<View style={{ paddingTop: 18 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{ height: 26, fontSize: 20, color: '#000', borderBottomWidth: 1, borderBottomColor: '#555' }}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
);
}
}
export default class App extends Component {
state = {
value: '',
};
handleTextChange = (newText) => this.setState({ value: newText });
render() {
return (
<View style={{ flex: 1, padding: 30, backgroundColor: '#f5fcff' }}>
<StatusBar hidden />
<FloatingLabelInput
label="Email"
value={this.state.value}
onChangeText={this.handleTextChange}
/>
</View>
);
}
}
is it possible to render a React.Component over other React.Component using just fat arrow function, using state seems unnecessary in my case as there is no need to close the opened Component. I am trying to achieve the simplest to render a React.Component over other React.Component.
I am trying to do it like this:
<Button onPress={() => { return (<ShowOtherReactComponent/>); }} >Show OtherComponent</Button>
this is calling the <ShowOtherReactComponent/> I know that because I called an alert function from constructor but! nothing is rendering. why is that? how can I do this?
PS: this approach may be wrong, but still wanna see how it can be done. for science.
You shouldn't return jsx from your handlers. Usually to show and or toggle components conditional rendering is the way to go.
Instead of returning <ShowOtherReactComponent/> from onPress you conditionally render the component based on a boolean binded to the local state and change the state instead.
const Component = () =>{
const [show, setShow] = useState(false)
const onPress = () => setShow(true)
return(
<>
<button onPress={onPress}> Show </button>
{ show && <ShowOtherReactComponent/> }
</>
)
}
I've made an example to show what you could potentially do if you wanted a button to add components to display:
import React from 'react';
import autoBind from 'react-autobind';
export default class ButtonTest extends React.Component {
constructor(props) {
super(props);
this.state = {
extraComponents : []
};
autoBind(this);
}
addComponent() {
const newComponent = (<p>I'm a new component</p>);
this.setState({extraComponents: [...this.state.extraComponents, newComponent]})
}
render() {
return (
<div>
<button onClick={this.addComponent}>add component</button>
{this.state.extraComponent}
</div>
)
}
}
I've checked it and it works.
import React, { useState } from 'react'
import { SafeAreaView, View, Text, Button, Dimensions } from 'react-native'
const App = () => {
const [visibilityOfOtherView, setvisibilityOfOtherView] = useState(false)
const { height, width } = Dimensions.get('window')
const SCREEN_HEIGHT = Math.round(height)
const SCREEN_WIDTH = Math.round(width)
return (
<SafeAreaView style={{ height: SCREEN_HEIGHT, width: SCREEN_WIDTH, }}>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'red' }}>
<Text style={{ marginBottom: 20 }}>
First Components
</Text>
<Button
title='Toggle Components View'
onPress={() => setvisibilityOfOtherView(!visibilityOfOtherView)}
/>
</View>
{
visibilityOfOtherView ?
<View style={{ height: SCREEN_HEIGHT, width: SCREEN_WIDTH, alignItems: 'center', justifyContent: 'center', backgroundColor: 'green' }}>
<Text style={{ marginBottom: 20 }}>
Secound Components
</Text>
<Button
title='Toggle Components View'
onPress={() => setvisibilityOfOtherView(!visibilityOfOtherView)}
/>
</View>
: null
}
</SafeAreaView>
)
}
export default App
I'm working on an app in React Native. I want to make it so the styling of the panel labels on the bottom of the screen updates based on the panel the user is on.
As of now, I can get the index of the current panel that's showing, but I don't know how to make that update the styling of the labels.
The first panel
and the second panel
Basically when you use the same component and want to style it in different ways, your component's style property depends on either props or state. There are many ways to put different styles depending on your state/props, I'll provide just a few of them:
Ternary operation based on current state.
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const styles = StyleSheet.create({ // Your styles go here
labelFirstTab: {
textColor: 'red',
},
labelSecondTab: {
textColor: 'blue',
},
});
class MyApp extends React.Component {
state = {
currentTab: 0,
};
getLabelStyles = () => {
const { currentTab } = this.state;
return currentTab === 0 ? styles.labelFirstTab : styles.labelSecondTab;
};
render() {
return (
<View style={{ flex: 1 }}>
{/* Let's say this is your label */}
<Text style={this.getLabelStyles()}>Hi! I'm a nice label.</Text>
</View>
);
}
}
Additional styling based on props (also could depend on state, it doesn't matter).
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
label: {
fontSize: 16,
textColor: 'black',
},
labelDarkMode: {
textColor: 'lightgrey',
},
}); // Your styles go here
class MyApp extends React.Component {
getLabelStyles = () => {
const { isDarkMode } = this.props;
const { label, labelDarkMode } = styles;
return [styles.label, isDarkMode && styles.labelDarkMode];
};
render() {
return (
<View style={{ flex: 1 }}>
{/* Let's say this is your label */}
<Text style={this.getLabelStyles()}>Hi! I'm a nice label.</Text>
</View>
);
}
}
You even can pass your styles directly from your props, leaving the whole logic to your parent component. Just make sure that you've passed styles from your parent component to the current one.
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
class MyApp extends React.Component {
render() {
const { labelStyles } = this.props;
return (
<View style={{ flex: 1 }}>
{/* Let's say this is your label */}
<Text style={labelStyles}>Hi! I'm a nice label.</Text>
</View>
);
}
}
Thank you E. Dn! This worked! Here's what I did.
const [activePanel, setActivePanel] = useState('nowPanel');
Swiping between panels calls a function:
const swipeNavigation = (index) => {
if (index === 0) {
setActivePanel('nowPanel');
} else {
setActivePanel('todayPanel');
}
};
Then within the actual View I want to style:
style={activePanel === 'nowPanel' ? styles.activePanel : null,}>
I trying to build a weather app for my training and I have a issues.
I got a Type Error whatever I do. what I intended to do is get a json data from weathermap api and then
show some strings but I couldn't.
here is main content from My app
import React, { Component } from 'react';
import { View, StyleSheet, Text } from 'react-native';
class Content extends Component{
constructor(props) {
super(props);
this.state = {
data: this.props.weather.main,
};
}
render() {
return (
<View style={styles.content}>
<Text style={styles.city}>City Name</Text>
<Text style={styles.itemsize}>Weather {this.state.data}</Text>
<Text style={styles.itemsize}>Description</Text>
<Text style={styles.itemsize}>Temperature Celsius</Text>
<Text style={styles.itemsize}>Pressure</Text>
<Text style={styles.itemsize}>Humidity</Text>
</View>
);
}
}
const styles = StyleSheet.create({
content: {
flex: 1,
justifyContent: 'center',
alignItems:'center'
},
city: {
fontSize: 50,
padding: 20
},
itemsize: {
fontSize: 30,
padding: 5
}
})
export default Content;
and this is my upper component which is trying to get data and pass down.
import React, { Component } from 'react';
import Content from './Content';
import GetWeather from './GetWeather';
class Home extends Component {
constructor(props) {
super(props);
this._getData.bind(this);
this._getData();
this.state = {
data: null,
};
}
_getData = () => {
GetWeather.getWeather().then( json => {
console.log(json);
this.setState({data: json});
});
};
render() {
return (
<Content weather={this.state.data}/>
);
}
}
export default Home;
and last one is code that I wrote to get api data from openweathermap
function getLocation(lat, long) {
return `${API_STEM}lat=${lat}&lon=${long}&appid=${APP_ID}`;
}
function getWeather() {
return fetch(getLocation(LATTITUDE,LONGGITUDE))
.then(response => response.json())
.then(responseJson => {
return { main: responseJson.weather[0].main};})
.catch(err =>console.log(err));
}
export default {getWeather: getWeather};
In your parent component, state never gets data and always remains null. When we want to fetch data from an API, we should use a react lifecycle method called componentDidMount(). So in your parent component, you should either call your _getdata function in componentDidMount or fetch your data in the lifecycle method, like below code which is a better way in my opinion. Also, never initially set your state to null. set it to an empty object.
import React, { Component } from 'react';
import Content from './Content';
import GetWeather from './GetWeather';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: {},
};
}
componentDidMount() {
GetWeather.getWeather().then( json => {
console.log(json);
this.setState({data: json});
});
}
render() {
console.log(this.state.data);
return (
<Content weather={this.state.data}/>
);
}
}
export default App
and then in your child component, you should either use one of updating lifecycle methods (that has risks) or you can change your child component to functional component, for you don't need state.
import React, { Component } from 'react';
import { View, StyleSheet, Text } from 'react-native';
function Content(props) {
return (
<View style={styles.content}>
<Text style={styles.city}>City Name</Text>
<Text style={styles.itemsize}>Weather {props.weather.main}</Text>
<Text style={styles.itemsize}>Description</Text>
<Text style={styles.itemsize}>Temperature Celsius</Text>
<Text style={styles.itemsize}>Pressure</Text>
<Text style={styles.itemsize}>Humidity</Text>
</View>
)
}
const styles = StyleSheet.create({
content: {
flex: 1,
justifyContent: 'center',
alignItems:'center'
},
city: {
fontSize: 50,
padding: 20
},
itemsize: {
fontSize: 30,
padding: 5
}
})
export default Content;
The main problem is that this.state.data in the Home component is set after the Content component is created (after its constructor function is called).
This will generate a TypeError because this.props.weather is undefined and you are trying to access a property this.props.weather.main.
The easiest way to solve this will be to use the props object directly instead of adding those props to the state, here is an example:
<Text style={styles.itemsize}>Weather {this.props.weather}</Text>
Before the request finishes you already set this.state.data inside Content to null and it will not get updated when the component re-renders because the constructor only runs once on mount.
Setting state from props is an anti pattern and should be used only in rare situations.
Instead, read the weather data from this.props which will get updated once the parent component updates his state
You would also need to check if this.props.weather is null before you access .main inside this.props.weather
class Content extends Component {
render() {
const { weather } = this.props
return (
<View style={styles.content}>
<Text style={styles.city}>City Name</Text>
<Text style={styles.itemsize}>
Weather {weather ? weather.main : null}
</Text>
<Text style={styles.itemsize}>Description</Text>
<Text style={styles.itemsize}>Temperature Celsius</Text>
<Text style={styles.itemsize}>Pressure</Text>
<Text style={styles.itemsize}>Humidity</Text>
</View>
)
}
}
I have a problem with making my ButtonGroup dynamic, I tried a lot but nothing seems to work, can someone help me, please?
import React from 'react';
import { ButtonGroup } from 'react-native-elements';
export default class WebsiteFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
WebsiteFilter: 3
};
}
updateIndex = ( WebsiteFilter ) => this.setState({ WebsiteFilter })
render() {
const buttons= ['Vergelijkdirect', 'Ivanhoe', 'Bespaarcoach'];
let { WebsiteFilter } = this.state;
return (
<ButtonGroup
textStyle={{ textAlign: 'center', fontSize: 12, }}
onPress={this.updateIndex}
WebsiteFilter={WebsiteFilter}
buttons={buttons}
/>
);
}
}
Instead of:
const buttons= ['Vergelijkdirect', 'Ivanhoe', 'Bespaarcoach'];
I need to display the domain of this array:
[{"id":127,"created_at":"2015-11-02 15:35:11","updated_at":"2016-09-19 11:42:10","deleted_at":null,"customer_id":66,"domain":"http:\/\/vergelijkdirect.com","google_id":"UA-97758230-1","currency_id":1,"root":1,"screenshot":"","integration_date":"2016-09-19 11:42:10"},{"id":283,"created_at":"2017-01-13 16:54:24","updated_at":"2017-01-13 16:54:24","deleted_at":null,"customer_id":66,"domain":"https:\/\/ivanhoe.io","google_id":null,"currency_id":1,"root":0,"screenshot":"","integration_date":null},{"id":327,"created_at":"2017-06-14 19:29:42","updated_at":"2017-06-23 17:29:01","deleted_at":null,"customer_id":66,"domain":"http:\/\/bespaarcoach.vergelijkdirect.com","google_id":"UA-39848260-2","currency_id":1,"root":0,"screenshot":"","integration_date":"2017-06-23 17:29:01"}]
The property buttons expects an array of strings or components, so in your case, you need to map the array and to return the property that you want to display:
data.map(e => e.id)
Also, the ButtonGroup component does not have a property WebsiteFilter, it has to be selectedIndex.
Your component should look like this:
<ButtonGroup
textStyle={{ textAlign: 'center', fontSize: 12, }}
onPress={this.updateIndex}
selectedIndex={this.state.WebsiteFilter}
buttons={data.map(e => e.id)}
/>
Here is a working demo.