I'm trying to make a timer with hooks but when I start the app, it's still counting only secs down, even if secs below 0. I couldn't find where the problem is
import React, { useState, useEffect } from 'react'
import { Text, View } from 'react-native'
export default App = () => {
const [mins, setMins] = useState(2)
const [secs, setSecs] = useState(2)
useEffect(() => {
setInterval(() => {
if (secs <= 0) {
if (mins <= 0) alert('end')
else {
setMins(m => m - 1)
setSecs(59)
}
}
else setSecs(s => s - 1)
}, 1000)
}, [])
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 40 }}>
{mins}:{secs < 10 && 0}{secs}
</Text>
</View>
)
}
This should work:
Don't forget to return from useEffect and clearInterval.
import React, { useState, useEffect } from 'react'
import { Text, View } from 'react-native'
export default App = () => {
const [mins, setMins] = useState(2)
const [secs, setSecs] = useState(2)
useEffect(() => {
const timerId = setInterval(() => {
if (secs <= 0) {
if (mins <= 0) alert('end')
else {
setMins(m => m - 1)
setSecs(59)
}
}
else setSecs(s => s - 1)
}, 1000)
return () => clearInterval(timerId);
}, [secs, mins])
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 40 }}>
{mins}:{secs < 10 && 0}{secs}
</Text>
</View>
)
}
Firstly, the React.useState, like the this.setState, it is an async function, you should not call them at the same time.
Secondly,React.useEffect like the componentDidMount,componentDidUpdate,componentWillMount. you have to return when the your condition is not match and clearInterval.
my solution code is the following:
import React, { useState, useEffect } from 'react'
import { Text, View } from 'react-native'
export default App = () => {
const [time, setTime] = useState({mins:2,secs:2})
useEffect(() => {
if(time.mins<0){ if(timerId) {clearInterval(timerId)} return}
const timerId = setInterval(() => {
if (time.secs <= 0) {
if (time.mins <= 0) {
setTime({...time,mins:time.mins-1,secs:time.secs})
alert('end')
}
else {
setTime({...time,mins:time.mins-1,secs:59})
}
}
else setTime({...time,mins:time.mins,secs:time.secs-1})
}, 1000)
return () => clearInterval(timerId);
}, [time])
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 40 }}>
{time.mins>=0 ? time.mins : 0}:{time.secs < 10 && 0}{time.secs}
</Text>
</View>
)
}
But for the react-native suggest way, the setState should use in the component,
the pure component should not React.useState, if you need it, you could use React. Component
Related
I have a counter that counts down, when the counter hits zero, I would like a style to change. The counter displays properly but the style never changes. How can I get the style to change when the counter hits a certain value?
Below is the code for a very basic example.
import React, { useState, useEffect } from "react";
import { Text, StyleSheet, SafeAreaView, TouchableOpacity, View } from "react-native";
const ActionScreen = () => {
const [timeLeft, setTimeLeft] = useState(4);
const [opac, setOpac] = useState(0.8);
useEffect(() => {
const interval = setInterval(() => setTimeLeft(timeLeft - 1), 1000);
if (timeLeft > 2) {
setOpac(0.8);
console.log("GT");
} else {
setOpac(0.5);
console.log("LT");
}
console.log("opac: ", opac);
if (timeLeft === 0) {
// clearInterval(interval);
setTimeLeft(4);
// setOpac(0.5);
}
return () => {
clearInterval(interval);
};
}, [timeLeft]);
return (
<SafeAreaView style={styles.container}>
<View style={styles.subActionContainer}>
<TouchableOpacity
style={[
styles.topButtons,
{
opacity: opac,
}
]}
>
<Text
style={styles.buttonText}>
{timeLeft}
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 25,
backgroundColor: 'black',
},
subActionContainer: {
flexDirection: "row",
alignContent: 'space-between',
},
topButtons: {
flex: 1,
backgroundColor: 'orange',
},
buttonText: {
fontSize: 18,
textAlign: 'center',
padding: 10,
color: 'white',
},
buttonFail: {
borderWidth: 1,
marginHorizontal: 5,
}
});
export default ActionScreen;
I'm fairly new to React-Native but read somewhere that some styles are set when the app loads and thus don't change but I have also implemented a Dark Mode on my app that sets inline styling, which works well. Why isn't the styling above changing?
Thank you.
you can create your timer and create a method isTimeOut and when it is true you can change the background
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import {useTimerCountDown} from './useCountDownTimer'
export default function App() {
const {minutes, seconds, setSeconds} = useTimerCountDown(0, 10);
const isTimeOut = Boolean(minutes === 0 && seconds === 0);
const handleRestartTimer = () => setSeconds(10);
return (
<View style={styles.container}>
<View style={[styles.welcomeContainer,isTimeOut &&
styles.timeOutStyle]}>
<Text>welcome</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: 10,
backgroundColor: '#ecf0f1',
padding: 8,
},
welcomeContainer:{
backgroundColor:'red',
},
timeOutStyle:{
backgroundColor:'blue',
}
});
See the useTimerCountDown hook here in this
working example
There is a count down timer activated by a play/pause button. setInterval is called in run passing in two functions countDown and vibrate. countDown decrements the state of the timer.
Within vibrate I want the phone to vibrate when the timer reaches a certain number, however, within vibrate "timer" is always 1500 until the pause button is pressed, and when play is pressed again "timer" is the value it had when paused.
In clockify which displays the time, "timer" is the current value of "timer" and the timer counts down.
I've read for hours here trying to fix this (which seems like a closure issue?) but could not come up with a solution, other than refactoring this into a class and use this.state
import { StatusBar } from 'expo-status-bar'
import React, { useState } from 'react'
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { AntDesign } from '#expo/vector-icons'
import { FontAwesome } from '#expo/vector-icons'
let intervalId = null
export default function App() {
const [timer, setTimer] = useState(1500),
[running, setRunning] = useState(false)
const reset = () => {
setTimer(1500)
setRunning(false)
clearInterval(intervalId)
}
const playPauseIcon = () => {
if (!running) {
return ( <FontAwesome name="play" style={styles.icons} /> )
} else {
return ( <FontAwesome name="pause" style={styles.icons} /> )
}
}
const playPause = () => {
if (!running) {
setRunning(true)
run()
} else {
setRunning(false)
this.clearInterval(intervalId)
}
}
const run = () => {
intervalId = setInterval(consolidateFunc, 1000)
}
const consolidateFunc = () => {
countDown()
vibrate()
}
const countDown = () => {
console.log("timer in countDown" + timer) // always logs 1500, 1500, 1500 until the play/pause button is pressed
setTimer(timer => timer - 1)
}
const vibrate = () => {
console.log("timer in buzz " + timer) // always logs 1500, 1500, 1500 until the play/pause button is pressed
if (timer < 1496) {
// vibrate
console.log("vibrate")
clearInterval(intervalId)
}
}
const clockify = () => {
console.log("timer in clock " + timer) //counts down 1500, 1499, 1498, etc.
const minutes = Math.floor(timer / 60),
seconds = timer % 60
if (seconds < 10 && minutes < 10) {
return "0" + minutes + ":" + "0" + seconds;
} else if (seconds < 10) {
return minutes + ":" + "0" + seconds;
} else {
return minutes + ":" + seconds;
}
}
return (
<View style={styles.container}>
<View style={styles.controls}>
<TouchableOpacity onPress={playPause} style={styles.reset}>{playPauseIcon()}</TouchableOpacity>
<TouchableOpacity style={styles.reset} onPress={reset}>
<FontAwesome name="undo" style={styles.icons} />
</TouchableOpacity>
</View>
<Text style={styles.status}>Time Remaining</Text>
<Text style={styles.timeLeft}>{clockify()}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
status: {
fontSize: 30,
paddingTop: 20
},
timeLeft: {
fontSize: 30
},
controls: {
flexDirection: "row",
alignItems: "center"
},
icons: {
fontSize: 25,
color: "black",
paddingLeft: 10
},
reset: {
paddingTop: 15,
paddingRight: 5,
paddingLeft: 5
}
});
View on snack: https://snack.expo.io/R1ST9Ct4U
I can make it work using a class but I would prefer not to if possible, it seems like there should be a way.
import { StatusBar } from 'expo-status-bar'
import React, { useState } from 'react'
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { AntDesign } from '#expo/vector-icons'
import { FontAwesome } from '#expo/vector-icons'
const defaultState = {timer: 1500, running: false };
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = defaultState
this.reset = this.reset.bind(this)
this.clockify = this.clockify.bind(this);
this.run = this.run.bind(this);
this.consolidateFunc = this.consolidateFunc.bind(this)
this.countDown = this.countDown.bind(this)
this.vibrate = this.vibrate.bind(this)
this.playPauseIcon= this.playPauseIcon.bind(this)
this.playPause = this.playPause.bind(this)
}
reset() {
this.setState(defaultState)
clearInterval(this.intervalId)
}
clockify() {
const minutes = Math.floor(this.state.timer / 60);
const seconds = this.state.timer % 60;
if (seconds < 10 && minutes < 10) {
return "0" + minutes + ":" + "0" + seconds;
} else if (seconds < 10) {
return minutes + ":" + "0" + seconds;
} else {
return minutes + ":" + seconds;
}
}
run() {
this.intervalId = setInterval(this.consolidateFunc, 1000);
}
consolidateFunc() {
this.countDown();
this.vibrate();
}
countDown() {
console.log("timer in countDown: " + this.state.timer)
this.setState({ timer: this.state.timer - 1 });
}
vibrate() {
console.log("timer in vibrate: " + this.state.timer)
if (this.state.timer < 1496) {
// vibrate
console.log("vibrate")
clearInterval(this.intervalId)
}
}
playPauseIcon() {
if (!this.state.running) {
return ( <FontAwesome name="play" style={styles.icons} /> )
} else {
return ( <FontAwesome name="pause" style={styles.icons} /> )
}
}
playPause() {
if (!this.state.running) {
this.setState({ running: true });
this.run();
} else {
this.setState({ running: false });
clearInterval(this.intervalId);
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.controls}>
<TouchableOpacity onPress={this.playPause} style={styles.reset}>{this.playPauseIcon()}</TouchableOpacity>
<TouchableOpacity style={styles.reset} onPress={this.reset}>
<FontAwesome name="undo" style={styles.icons} />
</TouchableOpacity>
</View>
<Text style={styles.status}>Time Remaining</Text>
<Text style={styles.timeLeft}>{this.clockify()}</Text>
<StatusBar style="auto" />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
status: {
fontSize: 30,
paddingTop: 20
},
timeLeft: {
fontSize: 30
},
controls: {
flexDirection: "row",
alignItems: "center"
},
icons: {
fontSize: 25,
color: "black",
paddingLeft: 10
},
reset: {
paddingTop: 15,
paddingRight: 5,
paddingLeft: 5
}
});
View as class on snack: https://snack.expo.io/mIG7TqB4I
I took a walk and the answer came to me.
The answer was to to eliminate the consolidateFunc, pass countDown to setInterval, move the code inside vibrate into useEffect, delete vibrate.
import { StatusBar } from 'expo-status-bar'
import React, { useState, useEffect } from 'react'
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { AntDesign } from '#expo/vector-icons'
import { FontAwesome } from '#expo/vector-icons'
let intervalId = null
export default function App() {
const [timer, setTimer] = useState(1500),
[running, setRunning] = useState(false)
const reset = () => {
setTimer(1500)
setRunning(false)
clearInterval(intervalId)
}
const playPauseIcon = () => {
if (!running) {
return ( <FontAwesome name="play" style={styles.icons} /> )
} else {
return ( <FontAwesome name="pause" style={styles.icons} /> )
}
}
const playPause = () => {
if (!running) {
setRunning(true)
run()
} else {
setRunning(false)
clearInterval(intervalId)
}
}
const run = () => {
intervalId = setInterval(countDown, 1000)
}
const countDown = () => {
setTimer(timer => timer - 1)
}
const clockify = () => {
//console.log("timer in clock " + timer)
const minutes = Math.floor(timer / 60),
seconds = timer % 60
if (seconds < 10 && minutes < 10) {
return "0" + minutes + ":" + "0" + seconds;
} else if (seconds < 10) {
return minutes + ":" + "0" + seconds;
} else {
return minutes + ":" + seconds;
}
}
useEffect(() => {
console.log("timer in useEffect " + timer)
if (timer < 1496) {
// vibrate
console.log("vibrate")
clearInterval(intervalId)
}
})
return (
<View style={styles.container}>
<View style={styles.controls}>
<TouchableOpacity onPress={playPause} style={styles.reset}>{playPauseIcon()}</TouchableOpacity>
<TouchableOpacity style={styles.reset} onPress={reset}>
<FontAwesome name="undo" style={styles.icons} />
</TouchableOpacity>
</View>
<Text style={styles.status}>Time Remaining</Text>
<Text style={styles.timeLeft}>{clockify()}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
status: {
fontSize: 30,
paddingTop: 20
},
timeLeft: {
fontSize: 30
},
controls: {
flexDirection: "row",
alignItems: "center"
},
icons: {
fontSize: 25,
color: "black",
paddingLeft: 10
},
reset: {
paddingTop: 15,
paddingRight: 5,
paddingLeft: 5
}
});
Here Home.js is Shows the both screen names
And Here Student.js screen is show only student contact numbers and Teacher.js
This is my full code..
And I have used navigation version 4
Navigation.js
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import Home from '../screens/Home'
import Teacher from '../screens/Teacher'
import Student from '../screens/Student'
const StackNavigator = createStackNavigator(
{
Student: {
screen: Student
},
Home: {
screen: Home
},
Teacher: {
screen: Teacher
}
},
{
initialRouteName: 'Home',
headerMode: 'none',
mode: 'modal'
}
)
export default createAppContainer(StackNavigator)
Home.js
import React from 'react';
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
export default class Home extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ marginTop: 50, fontSize: 25 }}>Home!</Text>
<View
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity
style={styles.button}
onPress={() => this.props.navigation.navigate('Teacher')}>
<Text>Teacher Numbers</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => this.props.navigation.navigate('Student')}>
<Text>Student Numbers</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
width: 300,
marginTop: 16,
},
});
Student.js
import React, { useState } from 'react'
import { StyleSheet, View, Button, FlatList } from 'react-native'
import { Text, FAB, List, IconButton, Colors, TextInput } from 'react-native-paper'
import { useSelector, useDispatch } from 'react-redux'
import { addnumber, deletenumber } from './../store/actions/studentList'
import Header from '../components/Header'
function StudentNumber({ navigation }) {
const [studentNumber, setStudentNumber] = useState('')
const snumbers = useSelector(state => state)
const dispatch = useDispatch()
const addNumber = number => dispatch(adbnumber(number))
const deleteNumber = id => dispatch(deletenumber(id))
function onSaveNumber() {
addNumber({studentNumber})
}
function FlatListItemSeparator () {
return (
//Item Separator
<View style={{height: 0.5, width: '100%', backgroundColor: '#C8C8C8'}}/>
);
};
function GetItem(item) {
//Function for click on an item
Alert.alert(item);
}
return (
<>
<View style={styles.container}>
<Button title="Go back" onPress={() => navigation.goBack()} />
<TextInput
label='Add a Number Here'
value={studentNumber}
mode='outlined'
onChangeText={setStudentNumber}
style={styles.title}
/>
{bnumbers.length === 0 ? (
<View style={styles.titleContainer}>
<Text style={styles.title}>You do not have any student numbers</Text>
</View>
) : (
<FlatList
data={snumbers}
ItemSeparatorComponent={FlatListItemSeparator}
renderItem={({ item }) => (
<List.Item
title={item.number.studentNumber}
descriptionNumberOfLines={1}
titleStyle={styles.listTitle}
onPress={() => deletestudentNumber(item.bid)}
/>
)}
keyExtractor={item => item.id.toString()}
/>
)}
<FAB
style={styles.fab}
small
icon='plus'
label='Add new number'
onPress={() => onSaveNumber()}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 10,
paddingVertical: 20
},
titleContainer: {
alignItems: 'center',
justifyContent: 'center',
flex: 1
},
title: {
fontSize: 20
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 10
},
listTitle: {
fontSize: 20
}
})
export default Student
Teacher.js
import React, { useState } from 'react'
import { StyleSheet, View, Button, FlatList } from 'react-native'
import { Text, FAB, List, IconButton, Colors, TextInput } from 'react-native-paper'
import { useSelector, useDispatch } from 'react-redux'
import { addnumber, deletenumber } from './../store/actions/teacherList'
import Header from '../components/Header'
function Teacher({ navigation }) {
const [teacherNumber, setTeacherNumber] = useState('')
const numbers = useSelector(state => state)
const dispatch = useDispatch()
const addNumber = number => dispatch(addnumber(number))
const deleteNumber = id => dispatch(deletenumber(id))
function onSaveNumber() {
addNumber({ teacherNumber})
}
function FlatListItemSeparator () {
return (
//Item Separator
<View style={{height: 0.5, width: '100%', backgroundColor: '#C8C8C8'}}/>
);
};
function GetItem(item) {
//Function for click on an item
Alert.alert(item);
}
return (
<>
<View style={styles.container}>
<Button title="Go back" onPress={() => navigation.goBack()} />
<TextInput
label='Add a Number Here'
value={teacherNumber}
mode='outlined'
onChangeText={setTeacherNumber}
style={styles.title}
/>
{numbers.length === 0 ? (
<View style={styles.titleContainer}>
<Text style={styles.title}>You do not have any teacher numbers</Text>
</View>
) : (
<FlatList
data={numbers}
ItemSeparatorComponent={FlatListItemSeparator}
renderItem={({ item }) => (
<List.Item
title={item.number.teacherNumber}
descriptionNumberOfLines={1}
titleStyle={styles.listTitle}
onPress={() => deleteNumber(item.id)}
/>
)}
keyExtractor={item => item.id.toString()}
/>
)}
<FAB
style={styles.fab}
small
icon='plus'
label='Add new number'
onPress={() => onSaveNumber()}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 10,
paddingVertical: 20
},
titleContainer: {
alignItems: 'center',
justifyContent: 'center',
flex: 1
},
title: {
fontSize: 20
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 10
},
listTitle: {
fontSize: 20
}
})
export default Teacher
studentStore.js
import { createStore } from 'redux'
import studentReducer from '../actions/studentList'
const studentStore = createStore(studentReducer)
export default studentStore
teacherStore.js
import { createStore } from 'redux'
import teacherReducer from '../actions/teacherList'
const teacherStore = createStore(teacherReducer)
export default teacherStore
teacherReducer.js
import remove from 'lodash.remove'
export const ADD_NUMBER = 'ADD_NUMBER'
export const DELETE_NUMBER = 'DELETE_NUMBER'
let numberID = 0
export function addnumber(number) {
return {
type: ADD_NUMBER,
id: numberID++,
number
}
}
export function deletenumber(id) {
return {
type: DELETE_NUMBER,
payload: id
}
}
const initialState = []
function teacherReducer(state = initialState, action) {
switch (action.type) {
case ADD_NUMBER:
return [
...state,
{
id: action.id,
number: action.number
}
]
case DELETE_NUMBER:
const deletedNewArray = remove(state, obj => {
return obj.id != action.payload
})
return deletedNewArray
default:
return state
}
}
export default teacherReducer
studetnReducer.js
import remove from 'lodash.remove'
export const ADD_NUMBER = 'ADD_NUMBER'
export const DELETE_NUMBER = 'DELETE_NUMBER'
let numberID = 0
export function addnumber(number) {
return {
type: ADD_NUMBER,
id: numberID++,
number
}
}
export function deletenumber(id) {
return {
type: DELETE_NUMBER,
payload: id
}
}
const initialState = []
function studentReducer(state = initialState, action) {
switch (action.type) {
case ADD_NUMBER:
return [
...state,
{
id: action.id,
number: action.number
}
]
case DELETE_NUMBER:
const deletedNewArray = remove(state, obj => {
return obj.id != action.payload
})
return deletedNewArray
default:
return state
}
}
export default studentReducer
I Have tried this but is working only for Teachers not for both..
When running the code below in react-native, I get a "buttonColor is read-only" error.
I've been reviewing documentation from various places on useState but am still not sure what is causing this particular error.
I would expect for the button to alternate between 'green' (the initial state) and 'red' after each subsequent tap, but it just show green on the first render and then I get the error message after the first tap.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonColor, setColor] = useState('green');
const changeColor = () => {
if (buttonColor='green') {
setColor('red')
} else if (buttonColor='red') {
setColor('green')
} else {
setColor('blue')
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:buttonColor, padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
Problem is you are assigning the value of button color instead of comparing it i.e using = instead of ===. You are basically setting a value to button color which is wrong.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonColor, setColor] = useState('green');
const changeColor = () => {
if (buttonColor==='green') { // use === instead of == //
setColor('red')
} else if (buttonColor==='red') { // use === instead of == //
setColor('green')
} else {
setColor('blue')
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:buttonColor, padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
In addition to the answer posted by Atin above, I also thought of a way to do this using numerical values and an array of colors which I ultimately chose to go with due to needing some underlying binary representation of the data.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonNumber, setNumber] = useState(0);
const colors = ['green','red']
const changeColor = () => {
if (buttonNumber<1) {
setNumber(buttonNumber => buttonNumber + 1)
} else {
setNumber(buttonNumber => buttonNumber - 1)
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:colors[buttonNumber], padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
HI there if you are in 2021 having this problem I want to show you something that I was doing wrong
In my case I was trying to use a handleChange function to setState look here below
const handleChange = (e) => {
setCustomerLogin({...customerLogin, [e.target.name]: e.target.value})
I was getting a setCustomerLogin is ready only and its because I wrapped the (e) in the above example.
Solution is
const handleChange = e => {
setCustomerLogin({...customerLogin, [e.target.name]: e.target.value})
I want to use this library for react-native but couldn't figure out how. The documentation link for react-native is broken. Can i use the library for react-native?
React-Spring can be used for react-native. They have updated it for all platform.
Try this out:-
yarn add react-spring#5.3.0-beta.0
import React from 'react'
import { StyleSheet, Text, View, TouchableWithoutFeedback } from 'react-native'
import { Spring, animated } from 'react-spring/dist/react-spring-native.esm'
const styles = {
flex: 1,
margin: 0,
borderRadius: 35,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
export default class App extends React.Component {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring native from={{ margin: 0 }} to={{ margin: flag ? 100 : 0 }}>
{props => (
<TouchableWithoutFeedback onPressIn={this.toggle}>
<animated.View style={{ ...styles, ...props }}>
<Text>It's working!</Text>
</animated.View>
</TouchableWithoutFeedback>
)}
</Spring>
)
}
}
`
For anyone with issues, try using a different import. This worked for me on expo's react native.
import React, { Component } from 'react';
import { Text, View, TouchableWithoutFeedback } from 'react-native';
import { Spring, animated } from 'react-spring/renderprops-native';
const AnimatedView = animated(View);
const styles = {
flex: 1,
margin: 0,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
export default class App extends Component {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring
native
from={{ margin: 0 }}
to={{ margin: flag ? 100 : 0 }}
>
{props => (
<TouchableWithoutFeedback onPressIn={() => this.toggle()}>
<AnimatedView style={{ ...styles, ...props }}>
<Text>{flag ? "true" : 'false'}</Text>
</AnimatedView>
</TouchableWithoutFeedback>
)}
</Spring>
);
}
}
The example below works.
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableWithoutFeedback} from 'react-native';
import { Spring, animated } from 'react-spring'
const AnimatedView = animated(View)
const styles = {
flex: 1,
margin: 0,
borderRadius: 35,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
type Props = {};
export default class App extends Component<Props> {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring native from={{ margin: 0 }} to={{ margin: flag ? 100 : 0 }}>
{props => (
<TouchableWithoutFeedback onPressIn={this.toggle}>
<AnimatedView style={{ ...styles, ...props }}>
<Text>It's working!</Text>
</AnimatedView>
</TouchableWithoutFeedback>
)}
</Spring>
);
}
}