I am trying to check if the user authorised the use of the camera and location and if he did not, then a simple screen should be render that let him know about it. The function getting invoked but the return statement return blank screen instead of the component.
NOTE :
I tried to use 'backgroundColor: 'black' ti see if the rendered and I can't even see the black background.
CODE:
componentWillMount() {
Permissions.checkMultiple(['camera', 'location']).then(response => {
//response is an object mapping type to permission
console.log('permission check')
console.log('response.camera', response.camera)
console.log('response.location', response.location)
if (response.camera === 'denied' || response.location === 'denied') {
return (
<View>
<Text>
Sorry you cant use this app without allowing Location and Camera permmision
to do it just go to Setting/Keepr and allow Location and Camera access for this app
</Text>
<Button title={'go to settings'} onPress={Permissions.openSettings}></Button>
</View>
)
}
})
}
You are trying to return a JSX in a componentWillMount... and inside the Promise callback. This simply won't work as you need to return JSX from render method. You can use the react-state to do that. Example:
class MyComponent extends React.Component {
constructor(props) {
this.state = {
response: {}
};
}
componentWillMount() {
Permissions.checkMultiple(["camera", "location"]).then(response => {
this.setState({ response });
});
}
render() {
const { response } = this.state;
if (response.camera === "denied" || response.location === "denied") {
return (
<View>
<Text>
Sorry you cant use this app without allowing Location and Camera
permmision to do it just go to Setting/Keepr and allow Location and
Camera access for this app
</Text>
<Button title={"go to settings"} onPress={Permissions.openSettings} />
</View>
);
}
return <p>something</p>;
}
}
Related
I have an async function that GET the notes from network, the problem that I have is that it tries to render an empty array of data, therefore I get this error saying that item.id is undefined because the array is empty. I tried to put a condition if (data.length === 0) return <Text>No Entries</Text> but then it does not re render anything, even though when I console.log(data) I can see the data has arrived. Is there any way to re render when data has arrived, or any other way around this?
export default class NoteList extends Component {
render() {
const { data} = this.props;
return (
<View style={styles.cardView}>
<FlatList
numColons={data.length}
data={data}
renderItem={({ item: { name, content, id } }) => {
return (
<View>
<NoteCard
name={name}
content={content}
/>
</View>
);
}}
keyExtractor={(item) => item.id}
/>
</View>
);
}
}
How to prevent this:
TypeError: TypeError: undefined is not an object (evaluating 'item.id')
I also get this error, but I think it is related to the management of the first problem.
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory
leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, the componentWillUnmount method,
The problem you have, lies in the parent where data is saved in the state. Therefor you get the warning about updating the state of an unmounted component. There are a lot of different ways to fix this. One way I like (because of the readability), is using a variable for when the component mounts. A simple example:
class News extends Component {
_isMounted = false;
constructor(props) {
super(props);
this.state = {
news: [],
};
}
componentDidMount() {
this._isMounted = true;
axios
.get('https://hn.algolia.com/api/v1/search?query=react')
.then(result => {
if (this._isMounted) {
this.setState({
news: result.data.hits,
});
}
});
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
...
}
}
Now when the data is set, the NoteList component will automatically get updated. However what happens when api call fails. To prevent stale data, I like to use conditional rendering. Just like you suggested:
export default class NoteList extends Component {
render() {
const { data } = this.props;
if (data) {
return (
<View style={styles.cardView}>
<FlatList
numColons={data.length}
data={data}
renderItem={({ item: { name, content, id } }) => {
return (
<View>
<NoteCard name={name} content={content} />
</View>
);
}}
keyExtractor={item => item.id}
/>
</View>
);
}
}
}
A common way to do this in React is to keep track of when data is being fetched. This can be done e.g. by having a isFetching field in your state:
// This would be your default state
this.state = {
isFetching: false
};
Then, when you fire off the request (preferably in componentDidMount) you set isFetching to true using:
this.setState({ isFetching: true });
And finally, when the data arrives, you set it to false again:
this.setState({ isFetching: false });
Now, in your render function you can do something like this:
render () {
return (
<div className="something">
<h3>Some content</h3>
{this.state.isFetching ? <LoadingComponent /> : (
<ul>
{listItems}
</ul>
)}
</div>
)
}
By using state, you don't have to worry about telling your component to do something, instead it reacts to changes in the state and renders it accordingly.
I want my value to change on the screen when button is pressed. It does change the variable value behind the scenes but has no effect for the outdated value shown on the screen.
export default class App extends Component {
render() {
this.state = {
myVariable: 'egs'
}
const changeValue = () => {
this.state.myVariable = "CHANGED??!!"
}
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
I expect to update value to the changed one instead of outdated one.
Move state initialization outside of render as well as the changeValue method
You also cannot mutate statue directly, instead use setState()
This should work:
export default class App extends Component {
state = {
myVariable: 'egs'
}
changeValue = () => {
this.setState({myVariable:"CHANGED??!!"})
}
render() {
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
this.state.myVariable = "CHANGED??!!"
change to
this.setState({ myVariable: "CHANGED??!!" })
I'm using react-native-highlight-words to highlight hashtagged words in my react-native app. It highlights required words properly but I want to make it clickable too which is not provided by this library. Means when I will click #positivewibes word, it redirect me to another page.
I've uploaded the image for reference here.
My Code
import Highlighter from 'react-native-highlight-words';
export default class LikeComponent extends Component {
constructor(props) {
super(props);
this.state = {
highlightWordArray: []
};
}
componentDidMount() {
postText = this.props.postData.details;
var regexp = new RegExp('#([^\\s]*)','g');
postText = postText.match(regexp);
if(postText != null) {
this.setState({highlightWordArray: postText});
}
}
render() {
return (
<Highlighter
highlightStyle={{color: 'red'}}
searchWords={this.state.highlightWordArray}
textToHighlight= {this.props.postData.details}
/>
)}
}
Any help is appreciated. Thank you.
You can fork and modify the library code by providing an additional prop - onPress in the file as
<Text
onPress={props.onPress}
key={index}
style={chunk.highlight && highlightStyle}
>
{text}
</Text>
and later use it as
<Highlighter
...// other props
onPress={// your redirect instance}
/>
I am currently working on a project in react native in which I have to retrieve data from firebase and display it in the form of Cards in the application. The data is retrieved and stored in the array(I have checked using alert and log). But when I try to map it to the render function. Nothing happens. No error.
constructor() {
super();
this.state={
items:[]
}
ref = firebase.database().ref("users/").orderByKey();
}
componentWillMount()
{
ref.on("value",(snapshot) => {
const itemss=[];
snapshot.forEach((childSnapshot) => {
var userkey = childSnapshot.key;
var userdata = childSnapshot.val();
itemss.push({
key:userkey,
ite:childSnapshot.val().ite,
});
});
this.setState({
items:itemss,
});
});
}
I think it might be a problem with async data collection from firebase but I am still unable to get this working. The code to show how it is displayed is:
<View>
{
this.state.items.map(function (i) {
return(
<View onPress={alert(i)} style=
{{marginLeft:100,height:50,
width:150,backgroundColor:'red'}}>
<Text style={{fontSize:50,color:'#000'}}>{i.ite}</Text>
</View>
);
})
}
</View>
Kindly tell me what am I missing in the above code.
I'm working on a project in react-native where I have troubles of accessing an element inside an object array by passing it as a prop where I want it to be used. Requirement is to get the name property out and set it to a text inside a flatlist.
The structure of my object array as follow.
[
{
"media1":[
{"name":"Lynn"},
{"name":"Michelle"},
{"name":"Carter"}
]
},
{
"media2":[
{"price":"23"},
{"price":"76"},
{"price":"39"}
]
}
]
This is how is pass this object array as a prop where I want it to be used
return (
<View>
<AlbumDetail data = {this.state.allData}/>
</View>
);
This is where I want it to be used
const AlbumDetail = (props) => {
return (
<View>
{console.log(props.data[0])} //Working
{console.log(props.data[0].media1[0].name)} //Not working
// Requirement as bellow
<Text>{wants to set the "name" here}</Text>
<Text>{wants to set the "price" here}</Text>
</View>
);
};
How can I achieve this ??
You might want to place two missing comma's.
One after:
{"name":"Michelle"}
And one after
{"price":"76"}
AlbumDetail has no way to know it has a property called data. You need to write AlbumDetail function as a React.Component class.
You are passing a JSON object into AlbumDetail, you need to call JSON.parse(data) before use it. UPDATE: .then(resp => resp.json()) is used to parse json.
Place console.log before return. The object you returned should be pure JSX components.
The code below should solve your problem:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
const url =
'http://purelight-prod.appspot.com/api/user/v2/browse/homescreendata';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: undefined,
};
}
componentDidMount() {
fetch(url)
.then(resp => resp.json())
.then(respJson => {
this.setState({
data: respJson,
});
})
.catch(err => {
console.error(err);
});
}
render() {
return (
<View style={{ flex: 1 }}>
<TestView data={this.state.data} />
</View>
);
}
}
class TestView extends React.Component {
render() {
!!this.props.data && console.log(console.log(data[0].healer[0].healerid));
return (
<View>
<Text>Hello World!</Text>
</View>
);
}
}
Edit:
Use componentDidMount(), because we like to display something (loading icon, etc), and then update the View when data arrived.
This is an async task. The data has to be held until it arrived. I use !!this.props.data && ..., so it only displays when it is not undefined.
Since the API response is a relatively big package, it will be much easier to work with, if you use TypeScript and create an object class to parse it.
I don't think the API helper package provides correct response in your code.