SOLVED!: Check the one reply below. It solves it. But, after you allow camera, when you click the button again, it won't prompt again, which is natural. You have to deny camera from the emulator or phone's settings again for it to prompt again.
I am basically trying to do this: a button, when clicked; it will prompt the user of camera permission, in react. In my current app here, it asks on first launch of the app. I tried various ways to implement it with button, but to no avail. But this code works, without error. Here is my app.js:
import React, {Component} from 'react'
import {StyleSheet, View, Text, Button} from 'react-native'
import {Permission, PERMISSION_TYPE} from 'D:/Reactdeneme/reacttest/src/AppPermission'
export default class App extends Component {
componentDidMount() {
Permission.checkPermission(PERMISSION_TYPE.camera)
//this the thing that prompts the camera permission. I want this in a button.
}
render() {
return (
<View style={styles.container}>
<Text style={{fontSize: 30}}>izinler</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
THIS PART IS PROBABLY OPTIONAL, so please don't be afraid of the long code blocks. Here is my AppPermissions.js aswell:
import {check, request, PERMISSIONS, RESULTS} from 'react-native-permissions';
import {Platform} from 'react-native'
const PLATFORM_CAMERA_PERMISSIONS= {
ios:PERMISSIONS.IOS.MICROPHONE,
android: PERMISSIONS.ANDROID.CAMERA
}
const REQUEST_PERMISSION_TYPE = {
camera: PLATFORM_CAMERA_PERMISSIONS
}
const PERMISSION_TYPE= {
camera: 'camera'
}
class AppPermission {
checkPermission= async (type): Promise<boolean> => {
console.log("AppPermission checkPermission type:", type)
const permissions = REQUEST_PERMISSION_TYPE[type][Platform.OS]
console.log("AppPermission checkPermission permissions:", permissions)
if(!permissions){
return true
}
try {
const result = await check(permissions)
console.log("AppPermission checkPermission result:", result)
if (result === RESULTS.GRANTED) return true
return this.requestPermission(permissions)
} catch (error) {
console.log("AppPermission checkPermission error:", error)
return false
}
}
requestPermission=async(permissions): Promise<boolean> => {
console.log("AppPermission requestPermission permissions:", permissions)
try {
const result = await request(permissions)
console.log("AppPermission requestPermission result:", result)
return result === RESULTS.GRANTED
}catch(error) {
console.log("AppPermission requestPermission error:", error)
return false
}
}
}
const Permission = new AppPermission()
export {Permission, PERMISSION_TYPE}
You should read more react-native docs.
Remove checkPermission in componentDidMount and add this to onPress props of Button.
import React, {Component} from 'react'
import {StyleSheet, View, Text, Button} from 'react-native'
import {Permission, PERMISSION_TYPE} from 'D:/Reactdeneme/reacttest/src/AppPermission'
export default class App extends Component {
checkPermission = () => {
Permission.checkPermission(PERMISSION_TYPE.camera);
}
render() {
return (
<View style={styles.container}>
<Text style={{fontSize: 30}}>izinler</Text>
<Button title="Check" onPress={this.checkPermission}/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
Related
when i press the sign in with google button it doesn't do anything
i followed https://docs.expo.io/versions/latest/sdk/google/
the iosClientId: 'my-id', is normally my google clientid but changed it for security reasons
import React, { Component } from 'react';
import {StyleSheet, Text, View, Button} from 'react-native';
class LoginScreen extends Component {
async signInWithGoogleAsync () {
try {
const result = await Expo.Google.logInAsync({
//androidClientId: YOUR_CLIENT_ID_HERE,
behavior: 'web',
iosClientId: 'my-id',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
return result.accessToken;
} else {
return { cancelled: true };
}
} catch (e) {
return { error: true };
}
}
render() {
return (
<View style={styles.container}>
<Button title={"Sign In With Google"}
onpress={() =>this.signInWithGoogleAsync()}
/>
</View>
);
}
}
export default LoginScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
}
});
I expect is when i press the Sign In With Google button it to let me sign in
but what im getting is the button not doing anything
Change your render function to this:
render() {
return (
<View style={styles.container}>
<Button title={"Sign In With Google"}
onPress={() =>this.signInWithGoogleAsync()}
/>
</View>
);
}
I am building an app for iOS with React native and I would like to know how to take a snapshot of a given screen. I have found this library but I don't know how to use it. Does anyone know how to ?
EDIT:
I used the following code to capture a screen using the library but I get the given error.
try {
captureRef(viewRef, {
format: "jpg",
quality: 0.8
})
.then(
uri => console.log("Image saved to", uri),
error => console.error("Oops, snapshot failed", error)
);
} catch (e) {
console.log(e);
}
The error
ReferenceError: viewRef is not defined
Does anybody know how to fix the error?
Thank you
Sure, but you have to read a little about what a ref is. If you are already using React hooks, check this: https://es.reactjs.org/docs/hooks-reference.html#useref
(if not, just search on how to create a ref in React with createRef)
Basically, a ref is something that will let you identify your component using the same variable even if the component re-renders. So, viewRef in your example should be a reference to a given element. Like:
import React, { useRef } from "react";
function MyComponent() {
const viewRef = useRef();
return <View ref={viewRef}>content</View>
}
So, your draft could be something like:
import React, { useRef } from "react";
import {Button, View, Text} from 'react-native';
import { captureRef } from "react-native-view-shot";
function useCapture() {
const captureViewRef = useRef();
function onCapture() {
captureRef(captureViewRef, {
format: "jpg",
quality: 0.9
}).then(
uri => alert(uri),
error => alert("Oops, snapshot failed", error));
}
return {
captureViewRef,
onCapture
};
}
function MyComponent() {
const { captureViewRef, onCapture } = useCapture();
return (
<>
<View ref={captureViewRef}><Text>content</Text></View>
<Button title="Save" onPress={onCapture} />
</>
);
}
As far as I know, this only generates a temporary file. If you want to see the capture saved into your device, you should use CameraRoll https://facebook.github.io/react-native/docs/cameraroll
I won't cover how to use it here, but it would be something like:
CameraRoll.saveToCameraRoll(uri); // uri being the path that you get from captureRef method
Just notice that your app must ask for proper permission before attempting to save to the device gallery.
hi this can be with the help of react-native-view-shot
this is my parent component
import React, {Component,useRef} from 'react';
import {Platform, StyleSheet, Text, View,Image,Button} from 'react-native';
import { captureRef, captureScreen ,ViewShot} from "react-native-view-shot";
import NewVd from './NewVd';
import Newved from './Newved';
export default class App extends Component {
constructor(){
super();
this.state={
item:null,
captureProcessisReady:false,
myView:false
};
this.func=this.func.bind(this);
}
componentDidMount(){
}
result1=()=>{
console.log("i am here ");
this.setState({captureProcessisReady:true});
}
func = (uri) => {
console.log('ADD item quantity with id: ', uri);
this.setState({item:uri,myView:true});
};
render() {
return (
<View style={styles.container}>
{/* <NewVd
func={this.func}/> */}
<Newved />
<Text>...Something to rasterize...</Text>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Button onPress={()=>this.result1()} title="press Me"/>
<View>
{this.state.captureProcessisReady?( <NewVd func={this.func}/>):null}
</View>
<View>
{this.state.myView?( <Image source={{uri:this.state.item !== null?`${this.state.item}`:'https://picsum.photos/200'}} style={{width:100,height:100}} />):null}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
this is my child component
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import ViewShot from "react-native-view-shot";
class NewVd extends Component {
constructor(props){
super(props);
}
onCapture = uri => {
console.log("do something with ", uri);
this.props.func(uri); //for the parent using callback
}
render() {
return (
<ViewShot onCapture={this.onCapture} captureMode="mount">
<Text>...Something to rasterize...</Text>
</ViewShot>
);
}
}
export default NewVd;
I am working on a react-native project where I am trying to fetch data from an api using axios library and display the data.So,my app first shows a splash screen and it then needs to navigate to a page which consists of tabs.The tabs will contain the data from the api.
So,I am trying to initialize my store in my Homepage which comes after the splash screen.I have my reducer and action defined separately in 2 different files.
App.js file
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SplashScreen from './src/components/SplashScreen';
import HomeScreen from './src/components/HomeScreen';
const Navigation = StackNavigator({
Splash: {
screen: SplashScreen
},
Home: {
screen: HomeScreen
}
})
export default Navigation;
My SplashScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
My HomeScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
Action.js file
import axios from 'axios';
export const FETCH_DATA = 'fetch_data';
const API = 'https://api.myjson.com/bins/fz62x';
export function fetchData() {
const request = axios.get(API);
return dispatch => {
return request.then((data) => {
dispatch({
type: FETCH_DATA,
payload: data
})
})
}
}
My reducer
import { FETCH_DATA } from './actions';
export default function(state={}, action) {
switch(action.type) {
case FETCH_DATA:
return {
...state,
action.payload
};
default:
return state;
}
}
Can anyon please tell me if this the correct way? If not, then what is the correct way?
I would say there is no correct or incorrect way to do this. But I can share kind of a pattern that I usually use.
First I would create separate folders for different files. Actions in actions folder, reducers in reducers folder etc... I would create separate constants.js file and configureStore.js file and put them inside the project root directory.
I would drop Axios library and would just use Fetch API for data fetching. Considering your code I would do the following.
Create configureStore.js file inside your project root directory. I recommend you to use Redux-Thunk. You can find more info from here.
configureStore.js
import { createStore, applyMiddleware } from 'redux';
import app from './reducers';
import thunk from 'redux-thunk';
export default function configureStore() {
let store = createStore(app, applyMiddleware(thunk))
return store
}
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { StackNavigator } from 'react-navigation';
import configureStore from './configureStore';
import HomeScreen from './screens/HomeScreen';
const NavigationApp = StackNavigator({
HomeScreen: { screen: HomeScreen }
})
const store = configureStore()
export default class App extends Component {
render() {
return (
<Provider store={store}>
<NavigationApp />
</Provider>
);
}
}
Let's create constants.js and we place it inside the project root directory.
constants.js
export const FETCHING_TODOS = 'FETCHING_TODOS';
export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';
Now let's move on and create our action file which would be put inside the actions folder. Let's name it something like fetchToDos.js. Let's create a simple function using Fetch API.
fetchToDos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
export function fetchToDos() {
return (dispatch) => {
dispatch(getTodos())
return(fetch('https://api.myjson.com/bins/fz62x'))
.then(res => res.json())
.then(json => {
return(dispatch(getToDosSuccess(json)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
function getToDos() {
return {
type: FETCHING_TODOS
}
}
function getToDosSuccess(data) {
return {
type: FETCH_TODOS_SUCCESS,
data
}
}
function getToDosFailure() {
return {
type: FETCH_TODOS_FAILURE
}
}
fetchToDos.js with Axios
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
import axios from 'axios';
export function fetchToDos() {
return (dispatch) => {
dispatch(getUser())
axios.get('https://api.myjson.com/bins/fz62x')
.then(function (response) {
// handle your response here, create an object/array/array of objects etc...
// and return it in dispatch(getToDosSuccess(data over here))
return(dispatch(getToDosSuccess(response.data)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
// rest is the same...
Moving on to reducers. Let's create two files - index.js, todos.js and put them inside reducers folder.
todos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
const initialState = {
todos: [],
isFetching: false,
error: false
}
export default function todosReducer(state = initialState, action) {
switch(action.type) {
case FETCHING_TODOS:
return {
...state,
isFetching: true
}
case FETCH_TODOS_SUCCESS:
return {
...state,
isFetching: false,
todos: action.data
}
case FETCH_TODOS_FAILURE:
return {
...state,
isFetching: false,
error: true
}
default:
return state
}
}
index.js
import { combineReducers } from 'redux';
import todos from './todos';
const rootReducer = combineReducers({
todos
})
export default rootReducer
Basically "heavy lifting" is done. I would only create one screen because let's assume that users would tap back button (Android) while at home screen, they would end up on that splash screen. So in this example I am going to use one screen only.
HomeScreen.js
import React, { Component } from 'react';
import {
View,
Text,
ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { fetchTodos } from '../actions/fetchTodos';
class HomeScreen extends Component {
componentDidMount() {
this.props.fetchTodos()
}
render() {
const { todos, isFetching } = this.props.todos
if (isFetching) {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<ActivityIndicator size={'large'} />
</View>
)
} else {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text>todos.length</Text>
</View>
)
}
}
}
function mapStateToProps(state) {
return {
todos: state.todos
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ fetchTodos }, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
I really hope that you find this concept useful because I can say from my experience that it helped me a lot when I first get started and it helped me to understand the whole concept of redux much better.
Sorry if there are any typos and errors. I was on a flow.
I've been trying to save an asyncstorage item, on touchableopacity onPress, then navigate to a react-native-camera screen.
Problem is: Camera screen get blank. I got the following error: Warning: Cannot update during an existing state transition (such as within 'render' or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are anti-pattern, but can be moved to 'componentWillMount'.
Warning points to lines 27, 36 and 41 (at AddParameters class)
Here is the code:
AddParameters.js
import React, { Component } from 'react';
import {
Text,
AsyncStorage,
View,
TouchableOpacity,
} from 'react-native';
class AddParameters extends Component {
constructor() {
super()
this.state = {
localIds: [
"data1",
"data2",
"data3",
"data4",
"data5",
"data6"
],
}
}
renderScreen = () => {
return (
<TouchableOpacity onPress={this._AddParameter(this.state.localIds[0])}>
<Text>Click Me</Text>
</TouchableOpacity>
);
}
_AddParameter = (ParameterId) => {
const { navigate } = this.props.navigation;
AsyncStorage.setItem("myparam", ParameterId);
navigate("CameraScreen");
}
render() {
return (
this.renderScreen()
);
}
}
export default AddParameters;
CameraScreen.js
'use strict';
import React, { Component } from 'react';
import {
AppRegistry,
Dimensions,
StyleSheet,
Text,
View,
Image,
AsyncStorage,
} from 'react-native';
import Camera from 'react-native-camera';
class CameraScreen extends Component {
constructor(props) {
super(props);
this.state = {
mystate: '',
};
}
renderCamera = () => {
return (
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={stylesCamera.container}
aspect={Camera.constants.Aspect.fill}>
</Camera>
);
}
render() {
return (
this.renderCamera()
);
}
}
const stylesCamera = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "transparent",
},
});
export default CameraScreen;
Any explanation would be helpfull. Thanks in advance.
On your AddParameters file try changing this:
<TouchableOpacity onPress={this._AddParameter(this.state.localIds[0])}>
To:
<TouchableOpacity onPress={() => this._AddParameter(this.state.localIds[0])}>
Need help guys, currently using exponent and accessing the Exponent.Facebook.logInWithReadPermissionsAsync for authentication. Anyone has a guide in setting up the project. I can't find the iOS folder since in the instruction of facebook sdk, I need to add few libraries on the project. Here's my main.js:
import Expo from 'expo';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Button } from 'react-native-elements';
class App extends React.Component {
authenticate = (token) => {
const provider = firebase.auth.FacebookAuthProvider;
const credential = provider.credential(token);
return firebase.auth().signInWithCredential(credential);
}
login = async () => {
const ADD_ID = 273131576444313
const options = {
permissions: ['public_profile', 'email'],
}
const {type, token} = await Expo.Facebook.logInWithReadPermissionsAsync(ADD_ID, options)
if (type === 'success') {
const response = await fetch(`https://graph.facebook.com/me?access_token=${token}`)
console.log(await response.json());
this.authenticate(token);
}
}
render() {
return (
<View style={styles.container}>
<Text>Open up main.js to start working on your app!</Text>
<Button
raised
onPress={this.login}
icon={{name: 'cached'}}
title='RAISED WITH ICON' />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Expo.registerRootComponent(App);
`
Try putting single quotes around the APP_ID