I'm a newbie in AWS Amplify, and just couldn't figure out how to make my App class wait for the user to sign in before loading all other navigation components and then make the authentication component disappear as well. I'm exporting my app with the withAuthenticator function. What would be the best way to do this? Tkx!
Tried to find examples of post-login operations, without success.
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Navigator />
);
}
}
export default withAuthenticator(App);
Navigation components are loaded over the Sign In screen. The sign in screen does not disappear after the user is signed in, being overlapped by other components.
I think I figured out the best way of doing that is using Authenticator instead of withAuthenticator:
class AppWithAuth extends Component {
state = {
authState: ''
};
render() {
return (
<View style = { styles.container }>
<Authenticator
amplifyConfig = {awsconf}
onStateChange = {authState => this.setState({ authState })}
>
{this.state.authState === 'signedIn' && <App />}
</View>
...
}
class App extends Component {
render() {
return (
<View style = { styles.container }>
<Navigator />
</View>
);
}
}
Related
I'm new to React Native and I want to pass state variable cartTotal from Cart component to the custom HeaderRight CartCounter component so that when I update cartTotal variable in Cart component changes are visible in CartCounter component where I show it. I don't wanna use Redux, but I know that is possible with Context Api. I did a long search to find an example similar to mine but I didn't find it. Can you show me how to use it in my case?
Here my code
Cart Component
export default class Cart extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTransparent: true,
headerTintColor: "black",
headerRight: () => {
return <CartCounter cartTotal={this.state.cartTotal} />
}
};
}
constructor (props) {
super(props);
this.state = {
cartTotal: 0
}
}
...
...
...
CartCounter Component
export default class CartCounter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<TouchableOpacity onPress={ this.onPress }>
<View style={ styles.root }>
<Text style={ styles.total }>{ cart total updates I want to see } </Text>
</View>
</TouchableOpacity>
)
}
}
...
...
...
Thanks in advance
use react context https://reactjs.org/docs/context.html to create a global state and seter
So, I've just figured out today that only changing state in a React Native app triggers a re-render of the component. I'm changing state, but I'm doing it from a child component, and it seems to getting stuck in some loop, and () => { this.setState({current_time:'whatever'}) doesn't seem to do anything at all. How can I change my App.js's current_time in state from TimePicker.js?
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker />
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity>
<View style={s.contain} onPress={
/*
set this.state.current_time in parent to the actual current time
this.setState({current_time:'changed'}) seems to cause an infinite loop?
() => { this.setState({current_time:'changed'}) } doesn't seem to do anything
*/
}>
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
ShowTime.js
class ShowTime extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<View style={s.contain}>
<Text>{this.props.current_time}</Text>
</View>
)
}
};
Create a function in App.js and pass it as prop to TimePicker Component and the purpose of this function should be to setState . e.g
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
currentTimeHandler = (newCurrentTime) => {
this.setState({current_time: newCurrentTime});
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker getTime={ this.currentTimeHandler }/>
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity onPress={() => this.props.getTime('changes will be passed here')}>
<View style={s.contain} >
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
The reason is the setState only set the existing states locally in the js file. that would be your Timepicker.
In your case TimePicker is a child(or sub branch) of App (Your app stores your state, by your current build, and will never be changed by a child). You will need create two functions one in TimePicker and another App. TimePicker will handle the data and send it, via prop, the App will receive the prop and then trigger another function to setState.
Pass data from child to parent in React
This is the best one i can find.
Best read this as well:
https://reactjs.org/docs/react-component.html
It does say, setState only affect to local states, your state you want to set is not local.
Index.js
I try do launch screen.
export default class LaunchScreen extends Component{
constructor(props){
super(props);
this.state= {
loaded:false
}
}
componentWillMount(){
Thread.load(v => this.setState({loaded:true}));
}
render(){
const { navigate } = this.props.navigation;
return(
<View style={styles.container}>
{this.state.loaded ? navigate("Form")
:
<View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
}
</View>
)}}
export default class thread{
static load(cb){
setTimeout(cb,3000);
}
}
when I use these codes I get the warning "can not update during an existing state transition". How to fix it?
You're trying to navigate inside a return, try to change your render code to this:
render(){
const { navigate } = this.props.navigation;
if(this.state.loaded) navigate("Form")
return(
<View style={styles.container}>
<View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
</View>
)
}
EDIT: But you should probably do the navigation part inside a shouldComponentUpdate() checking if the nextState.loaded is different from your this.state.loaded and is true, like:
shouldComponentUpdate(nextProps, nextState){
if((nextState.loaded!=this.state.loaded)&&nextState.loaded){
navigate("Form")
return true
}
return false
}
I see a couple problems, but I don't think these are your main problems.
You can only have one default export, so if both classes are actually in a single file, remove the "default" from the thread class.
Pretty sure all class names must begin with a capital letter in React, so change "thread" to "Thread"
But I think your actual problem is that you're calling navigate('Form') directly from within the render. Try adding a handleNavigation class method and calling this.handleNavigation there instead. So you'd be left with something like this...
export default class LaunchScreen extends Component {
state = {
loaded: false
}
componentWillMount() {
Thread.load( () => this.setState({loaded: true}));
}
handleNavigation = () => {
this.props.navigation('Form');
}
render() {
return (
<View style={styles.container}>
{
this.state.loaded
? this.handleNavigation
: <View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
}
</View>
);
}
}
export class Thread {
static load(cb){
setTimeout(cb,3000);
}
}
I am learning react-native navigation https://reactnavigation.org/docs/intro/ . I see in examples there
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
I could not understand what exactly this line of code is for const { navigate } = this.props.navigation;
syntax has nothing to do with React Native
it is called Destructuring assignment in es6 / es2015
const { navigate } = this.props.navigation;
is equivilent to with exception to var and const .
var navigate = this.props.navigation.navigate
the example without Destructuring should look like this
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => this.props.navigation.navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
Include on your ServiceAction the this.props.navigation something like this:
<HomeScreen navigation={this.props.navigation}/>
because the props.navigation are by default on your parent component
and on HomeScreen component you will access to navition like:
..
goToSignUp() {
this.props.navigation.navigate('SignUp');
}
..
For me also was confusing before. Cheers!
Let's assume I have this custom component:
export default class Button extends Component {
render(){
return(
<TouchOpacity>
<Text> Button </Text>
</TouchOpacity>
)
}
}
And I use it in a parent component like this :
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
For some reason (unknown to me at least) this onPress even won't happen.
I'm pretty new to react-native btw. I believe I must find a way to enable this kind of event handling.
Is it possible to get a small example how to achieve that based on my examples above ?
So, just found out how to handle this.
export default class Button extends Component {
constructor(props){
super(props)
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
and
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
Long story short: since the onPress I'm passing is a prop in the MainPage, I'm passing it a function (this.doSomething) which later on is activated in Button's onPress.
Nick's answer is right.Along with that if you want to call separate function for both child and parent component then you can use onPressOut. This will help to manage state of componant
export default class Button extends Component {
constructor(props){
super(props)
}
onClickListen = () => {
if (this.state.isSelected === false) {
this.setState({isSelected:true});
isSelectedPass=true;
}
else {
this.setState({isSelected:false});
isSelectedPass=false;
}
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress} onPressOut={this.onClickListen}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
export default class MainPage extends Component {
render(){
return(
<Button onPress={ ()=>this.doSomething }></Button>
)
}
}