I'm using react native with expo and I received user name via facebook login code is here :
export default class FacebookLogin extends Component {
constructor(props) {
super(props);
this.state = { userInfo: null };
}
_handleFacebookLogin = async () => {
try {
const { type, token } = await Facebook.logInWithReadPermissionsAsync(
'my own app is not a problem',
{ permissions: ['public_profile'] }
);
switch (type) {
case 'success': {
const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}`
);
const userInfo = await response.json();
this.setState({ userInfo });
Alert.alert('Logged in!', `Hi ${userInfo.name}`);
this.props.facebookloginpress();
break;
}
case 'cancel': {
Alert.alert('Cancelled!', 'Login was cancelled!');
break;
}
default: {
Alert.alert('Oops!', 'Login failed!');
}
}
} catch (e) {
Alert.alert('Oops!', 'Login failed!');
}
};
render() {
return (
<View style={styles.container}>
<Button
title="Login with Facebook"
onPress={this._handleFacebookLogin}
/>
</View>
);
}
}
it is okay not a problem but I want to pass userInfo.name to my Profile screen and to print as a text on my profile screen, profil screen code is here:
export default class Profile extends React.Component {
constructor(props) {
super(props);
}
handleSignOutPress = () => {
this.props.navigation.navigate('LoginScreen');
};
render() {
return (
<View style={{ flex: 1, justifyContent: 'space-around' }}>
<Text>This text take a facebook username</Text>
<Button
backgroundColor="#03A9F4"
title="SIGN OUT"
onPress={this.handleSignOutPress}
/>
</View>
);
}
}
// thanks for your help
Related
I'm new to react native and want to make one function change state for the clicked button only not others that have the same function
as I explained in the title here is an example code
please any help & I know it might be a selly question but any answer will help
thanks a lot
export default class App extends Component {
constructor(){
super();
this.state = {
opened: true,
}
}
componentHideAndShow = () =>{
this.setState(previousState => ({opened: !previousState.opened}))
}
render() {
return (
{
this.state.opened ? <Text> hello</Text> : <Text> hello sdfsdfsdf</Text>
}
<Text onPress={this.componentHideAndShow}>test</Text>
{
this.state.opened ? <Text> hello</Text> : <Text> hello sdfsdfsdf</Text>
}
<Text onPress={this.componentHideAndShow}>test</Text>
);
}
}
This should work.
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
opened: [true, true]
};
}
componentHideAndShow = index => {
const opened = this.state.opened;
opened[index] = !opened[index];
this.setState({ opened: opened });
};
render() {
return (
<View>
{this.state.opened[0] ? (
<Text> hello</Text>
) : (
<Text> hello sdfsdfsdf</Text>
)}
<Button onPress={() => this.componentHideAndShow(0)}>test</Button>
{this.state.opened[1] ? (
<Text> hello</Text>
) : (
<Text> hello sdfsdfsdf</Text>
)}
<Button onPress={() => this.componentHideAndShow(1)}>test</Button>
</View>
);
}
}
Edit: you can do like this if you don't know the number of items:
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
const myArrayOfStrings = ['hello1', 'hello2', 'hello3', 'hello4', 'hello5'];
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
opened: undefined
};
}
componentDidMount() {
let opened = [];
myArrayOfStrings.map(item => {
opened.push(true);
});
this.setState({ opened: opened });
}
componentHideAndShow = index => {
const opened = this.state.opened;
opened[index] = !opened[index];
this.setState({ opened: opened });
};
render() {
const output = myArrayOfStrings.map((item, index) => {
return (
<View>
<Text>
{this.state.opened[index]
? `${item} is opened`
: `${item} is opened`}
</Text>
<Button onPress={() => this.componentHideAndShow(0)}>test</Button>
</View>
);
});
return <View>{output}</View>;
}
}
I didn't understand how to make the AsyncStorage work.
I use react-native-router-flux
Basically I have 3 pages:
FirstPage
export default class Authentication extends Component {
render() {
return (
..........
<TouchableOpacity
style ={[style.button, style.buttonOK]}
onPress={() => Actions.login() }>
<Text style={style.buttonTesto}>LOGIN</Text>
</TouchableOpacity>
<TouchableOpacity
style ={[style.button, style.buttonOK]}
onPress={() => Actions.signup() }>
<Text style={style.buttonTesto}>SIGNUP</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Login
login() {
let ctrl = true;
......
if (ctrl) {
let formdata = new FormData();
const identity = {
AppName: {
Username: this.state.username,
Password: this.state.password
}
};
formdata.append("Identity", JSON.stringify(identity));
fetch(APILINK , {
method: "POST",
headers: {
"Content-Type": "multipart/form-data"
},
body: formdata
})
.then(response => response.json())
.then(responseData => {
if (responseData.Error) {
.......
} else {
global.utente = new Utente(responseData);
Actions.homepageutente();
}
})
.catch(err => alert("err:" + err));
}
}
Utente
export default class Utente {
constructor(data) {
Utente.saveUtenteLoggato(data);
this._data = data;
....
);
}
get data() {
return this._data;
}
//there is a function for the signup there//
.......
static async saveUtenteLoggato(value) {
try {
await AsyncStorage.setItem("#UtenteLoggato", JSON.stringify(value));
} catch (error) {
console.log(error.message);
}
}
static async getUtenteLoggato() {
try {
return await AsyncStorage.getItem("#UtenteLoggato");
} catch (error) {
console.log(error.message);
return null;
}
}
static async clearUtenteLoggato() {
try {
global.utente = null;
await AsyncStorage.removeItem("#UtenteLoggato");
} catch (error) {
console.log(error.message);
return null;
}
}
}
So in Utente I have created the Asyncstorage function, but I don't understand how I should do when I close the app in backgroun (for example) to maintain the login active. At the moment if I go back in the App I should do another time the Login.
How can I solve it?
EDIT
Starting page
class Starting extends Component {
constructor(props)
{
super(props)
this.state = {
loading: true
}
}
componentWillMount() {
Utente.getUtenteLoggato()
.then(dataUtenteLoggato => {
if (dataUtenteLoggato !== null) {
global.utente = new Utente(JSON.parse(dataUtenteLoggato));
} else {
Actions.authentication();
}
})
.catch(err => {
console.log(err);
})
.finally(() => {
this.setState({ loading: false });
});
}
render() {
return(
<View style={style.container}>
<Spinner visible={this.state.loading} textContent={"Loading..."} textStyle={{color: '#FFF'}} />
</View>
);
}
}
You can implement splash screen component and check auth in componentWillMount. As example - get data from AsyncStorage, then perform request to check that user is authenticated and fetch user details. If auth data(e.g. auth token) is absent in storage or server threw auth error(in case when token is invalid or expired), redirect user to login screen, else mark user as authenticated and show main screen.
I have a variable in state called isLoading. The idea is to display a loading message while the program is communicating the server, then display the data. However, at ling 24, I get an error:
TypeError: This.setState is not a function (in 'this.setState({ isloadin: false});
import React from "react";
import { StyleSheet, Text, View, AsyncStorage } from "react-native";
var text;
export default class App extends React.Component {
constructor(props) {
super(props);
state = {
isLoading: true
};
}
componentDidMount = () => {
AsyncStorage.getItem("accessToken").then(token => {
postdata(
"http://1.0.0.0:1337/loadTransactions",
{ UserID: 69 },
function(result) {
text = toString(result.Data[1].ID);
text = result.Data[1].Label;
console.log(result.Data[1].Label);
this.setState({
isLoading: false
});
}
);
});
};
render() {
console.log(this.setState.isLoading);
if (this.setState.isLoading) {
console.log(this.setState.isLoading);
return (
<View style={styles.container}>
<Text>Loading....</Text>
</View>
);
} else {
return (
<View style={styles.container}>
<Text>Hi, {text}</Text>
<Text>Test</Text>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
To maintain the context of a function as the same context where the function was lexically defined, you have to use an arrow function:
componentDidMount = () => {
AsyncStorage.getItem("accessToken").then(token => {
postdata(
"http://204.48.23.161:1337/loadTransactions",
{ UserID: 69 },
function(result) {
// ^^^^^^^ use `result => ` here
text = toString(result.Data[1].ID);
text = result.Data[1].Label;
console.log(result.Data[1].Label);
this.setState({
isLoading: false
});
}
);
});
};
this (ref to the instance of class) might not be available inside the context of AsyncStorage. Save this as another variable and use inside:
componentDidMount = () => {
const self = this;
AsyncStorage.getItem("accessToken").then(token => {
postdata(
"http://204.48.23.161:1337/loadTransactions",
{ UserID: 69 },
function(result) {
text = toString(result.Data[1].ID);
text = result.Data[1].Label;
console.log(result.Data[1].Label);
self.setState({
isLoading: false
});
}
);
});
};
)
I am programming a Notes App. The Note is saved when navigating back to the homescreen (away from Note Edit Component). The List of the Notes Titles (in HomeScreen) is updated onWillFocus. The Problem is the note save is async and takes some time... so onWillFocus updates the list BEFORE the note is saved. Now i want to call the list update manually when the note save resolves. But I have no idea how to do that.
I have one db file where all database functions live in. And two components.
Now i need to call a function in the HomeScreen Component from the db file.
that is my db file (removed other functions)
//db imports and making a const db
export function updateNote(updateStuff) {
db.get(_id).then(function(doc) {
return db.put({
//updateStuff
});
}).then(async function(response) {
console.log(response)
//here i need to call the function
}).catch(function (err) {
console.log(err);
});
}
and this is my HomeScreen Component
import React from 'react';
import {
//all elements
} from 'react-native';
import { NavigationEvents } from 'react-navigation';
import { putNote, getAllNotes, deleteAllNotes } from './db/db.js';
export default class HomeScreen extends React.Component {
state = {
notes: [],
}
async renderAllNotes() {
let result = await getAllNotes();
this.setState({notes: result.rows});
}
render() {
return (
<View style={styles.container}>
<NavigationEvents
onWillFocus={() => this.renderAllNotes()}
/>
<FlatList
//Flat List Code
/>
</View>
);
}
}
Here is my Note Edit component:
import React from 'react';
import {
//stuff
} from 'react-native';
import { updateNote, getNote, getAllNotes } from './db/db.js';
export default class NoteScreen extends React.Component {
state = {
_id: this.props.navigation.getParam('_id'),
}
updateThisNote() {
updateNote(this.state._id, this.state.title, this.state.content, this.state.createdAt);
}
componentWillUnmount() {
this.updateThisNote();
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ title: text })}
value={this.state.title}
/>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ content: text })}
value={this.state.content}
/>
<Button
title='update Note'
onPress={() => this.updateThisNote()}
/>
</View>
);
}
}
and now renderAllNotes should be calln when updateNote resolves.
I already tried importing the HomeScreen class in the db file and calling the function as well as trying to export the render allNotes function an import it in the db file. Without success ;(
Thank you for every help ;)
EDIT:
async putNoteAndPushRoute() {
let resolve = await putNote("");
this.props.navigation.navigate('Note', {
_id: resolve.id,
renderAllNotes: this.renderAllNotes.bind(this),
});
}
Error Message: _this2.props.renderAllNotes is not a function
You can pass the this.renderAllNotes() to your edit component.
Like this.
...
renderAllNotes(){
....
}
...
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Button onPress={() =>{
navigate('Edit',{
renderAllNotes: this.renderAllNotes.bind(this)
});
}} />
</View>
)
}
...
And then inside your edit,
you can just call the renderAllNotes after the note is updated. But you need to change your updateNote to return a promise
updateThisNote(){
// Make sure your updateNote returns a promise
updateNote(this.state._id, this.state.title,
this.state.content, this.state.createdAt)
.then(() => {
const { params} = this.props.navigation.state;
params.renderAllNotes();
});
}
componentWillUnmount() {
this.updateThisNote();
}
you can change your update function to return a promise
export function updateNote(updateStuff) {
return new Promise(function(resolve, reject) {
db.get(_id).then(function(doc) {
return db.put({
//updateStuff
});
}).then(async function(response) {
console.log(response)
//resolve it here
resolve();
}).catch(function (err) {
console.log(err);
});
}
}
This would solve your issue.
I'm developing a mobile application by use react-native and redux,thunk and it's the first time I write by react-native.
My problem is I call an api and the response is valid, I want to do somethings as update UI, navigate to new screen... for do that I will need to used flag in my component to mark it.
This is login example, after user login success, i want to navigate to Home screen. for do that, i need check an flag isLoginSuccess in props on the method componentWillReceiveProps to know user have been login success or not, but i think it's not good solution.
My question is we have other way to do it without use flag.
action.js
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const LOGIN = "LOGIN";
export function login(username, password) {
console.log(username)
return {
type: LOGIN,
username: username,
password: password
}
}
export function loginSuccess(data) {
return {
type: LOGIN_SUCCESS,
loginData: data
}
}
export function loginFail(error) {
return {
type: LOGIN_FAIL,
error: error
}
}
export function doLogin(username, password) {
return (dispatch) => {
dispatch(login(username, password))
api.login(username, password)
.then(response => response.json())
.then(jsonData => {
console.log(jsonData)
dispatch(loginSuccess(jsonData))
})
.catch((error) => {
dispatch(loginFail(error))
})
}
}
reducer.js
const initialState = {
loginData:{},
isLoginDoing : false,
isLoginSuccess : false,
username :"",
password : "",
error : {},
}
export default function(state = initialState , action ={}){
switch(action.type){
case actionType.LOGIN:{
return {
...state,
username: action.username,
password: action.password,
isLoginDoing : true
}
}
case actionType.LOGIN_SUCCESS:{
return {
...state,
loginData: action.loginData,
isLoginDoing : false,
isLoginSuccess : true
}
}
case actionType.LOGIN_FAIL:{
return {
...state,
isLoginDoing : false,
isLoginSuccess : false,
error : action.error
}
}
default :{
return state
}
}
}
component.js
import { connect } from "react-redux"
import { bindActionCreators } from 'redux';
import { doLogin } from '../actions'
import BaseComponent from './baseComponent'
class Login extends BaseComponent {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
}
this.functionLogin = this.functionLogin.bind(this);
}
functionLogin() {
const { username, password } = this.state;
if(!this.props.loginReducer.isLoginDoing){
this.props.doLogin(username, password)
}
}
componentWillReceiveProps (nextProps) {
console.log("componentWillReceiveProps");
const { navigate, goBack } = this.props.navigation;
if(nextProps.loginReducer.isLoginSuccess){
// this._navigateTo('Home')
navigate('Home',nextProps.loginReducer.loginData);
}
}
render() {
const { navigate, goBack } = this.props.navigation;
return (
<View style={{ backgroundColor: 'color', marginTop: 10 }} >
<TextInput
style={{ height: 40 }}
placeholder="Username"
onChangeText={value => this.setState({ username: value })}
/>
<TextInput
style={{ height: 40 }}
placeholder="Password"
onChangeText={value => this.setState({ password: value })}
/>
<Button
onPress={this.functionLogin}
title="Login"
color="#841584"
/>
</View>
);
}
}
const mapStateToProps = (state) => {
console.log(state);
return {
loginReducer: state.loginReducer
};
}
function mapDispatchToProps(dispatch) {
return {
doLogin: (username, password) => dispatch(doLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
Thanks
In your function doLogin, you can dispatch a navigation action after dispatch(loginSuccess(jsonData)).
For example for react-navigation (if you have integrated it with redux, if it's not the case, see https://reactnavigation.org/docs/guides/redux):
dispatch(NavigationActions.navigate({routeName: 'Home'});
(Don't forget import { NavigationActions } from 'react-navigation';)