React Native - Activity Indicator while FlatList loads images - react-native

Whenever my app mounts, I have set:
constructor(props) {
super(props);
this.state = {
loading: true
};
}
I have an activity indicator which animates until loading: false:
{this.state.loading &&
<View style={styles.loading}>
<ActivityIndicator color="red" animating={this.state.loading} />
</View>
}
I tried searching inside FlatList's documentation for a method would tell me if all items have been rendered so I can call this.setState({loading: false}); However, I did not manage to find such method.
Does anyone know how can I display my activity indicator whilst the list is loading its data?

Your problem is not react native related. Which is why you couldn't find any help regarding it in the react native documentation.
Assuming that your data is coming in asynchronously and in reference to your question you are not able to figure out when this asynchronous operation ends.
Use promises or async await or any other functionality like that, to figure out when this asynchronous operation ends and then use setState to disable the activity indicator and then show the flatList.
Let me know if you need more explanation or clarity on the above said.

Related

Simplified style change onPress React Native

The following is a first attempt at learning to simply change the style of an element onPress in react native. Being well versed in web languages I am finding it difficult as it is not as straight forward.
For reasons as yet unknown, the element requires two clicks in order to execute.
export class NavTabItem extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
}
this.NavTabAction = this.NavTabAction.bind(this)
}
NavTabAction = (elem) => {
elem.setState({active: !elem.state.active})
}
render() {
return (
<TouchableOpacity
style={this.state.active ? styles.NavTabItemSelected : styles.NavTabItem}
onPress={()=> {
this.NavTabAction(this)
}}>
<View style={styles.NavTabIcon} />
<Text style={styles.NavTabLabel}>{this.props.children}</Text>
</TouchableOpacity>
);
}
}
Other issues:
I also have not worked out how a means of setting the active state to false for other elements under the parent on click.
Additionally, Is there a simple way to affect the style of child elements like with the web. At the moment I cannot see a means of a parent style affecting a child element through selectors like you can with CSS
eg. a stylesheet that read NavTabItemSelected Text :{ // active style for <Text> }
Instead of calling elem.setState or elem.state, it should be this.setState and elem.state.
NavTabAction = (elem) => {
this.setState(prev => ({...prev, active: !prev.active}))
}
And instead of passing this in the onPress, you should just pass the function's reference.
onPress={this.NavTabAction}>
You should also remove this line because you are using arrow function
// no need to bind when using arrow functions
this.NavTabAction = this.NavTabAction.bind(this)
Additionally, Is there a simple way to affect the style of child elements like with the web
You could check styled-component, but I think that feature don't exists yet for react native. What you should do is pass props down to child components.
Thanks to everyone for their help with this and sorting out some other bits and pieces with the code.
The issue in question however was that the style was changing on the second click. A few hours later and I have a cause and a solution for anyone suffering from this. Should any of the far more experienced people who have answered this question believe this answer is incorrect or they have a better one, please post it but for now here is the only way I have found to fix it.
The cause:
Using setState was correctly re rendering the variables. This could both be seen in the console via console.log() and directly outputted in the render making them visible.
However, no matter what was tried, this did not update the style. Whether it was a style name from the Stylesheet or inline styles, they would update on the second click rather than the first but still to the parameters of the first. So if the first click should make a button turn from red to green, it would not do so even though the new state had rendered. However if a subsequent click should have turned the button back to red then the button would now go green (like it should have for the first click). It would then go red on the third click seemingly always one step behind the status passed to it.
Solution
To fix this, take the style off the the primary element (forgive terminology, someone edit), in my case, the TouchableOpacity element. Add in a child View element and place the styles on that View element instead along with the ternary operator and wallah.
It seems any change to status on the effective master element or container if you prefer, only takes affect after another render, not that contained in setStatus.
Final code:
export class NavTabItem extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
}
}
NavTabAction = () => {
this.setState({active: !this.state.active})
}
render() {
this.state.active == true ? console.log("selected") : console.log("unselected")
return (
<TouchableOpacity onPress={this.NavTabAction}>
// added View containing style and ternary operator
<View style={this.state.active == true ? styles.NavTabItemSelected : styles.NavTabItem}>
<View style={styles.NavTabIcon} />
<TextCap11 style={styles.NavTabLabel}>{this.props.children}</TextCap11>
</View>
// End added view
</TouchableOpacity>
);
}
}

React-Native: How to know when the rendering got finished

I have FlatList in render() function with a reference,
<FlatList
ref={(ref) => { this.flatListRef = ref }}
data={this.state.data}
renderItem={({ item, index }) => this.renderOuterCard(item, index)}
/>
I need to use this.flatListRef to call FlatList's methods, which is possible only when FlatList is rendered. Otherwise following error occurs,
Cannot read the property 'ScrollToIndex' of undefined
(I tried to call FlatList's ScrollTOIndex method)
Infact I called ScrollTOIndex in componentDidMount() method , But still this error occurs. Hence, This is clear that componentDidMount() is called before render() finishes completely.
Can anybody let me know when rendering finishes exactly?
This is clear that componentDidMount() is called before render() finishes completely.
According to this schema the first render phase occur before componentDidMount.
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
 Live example:
https://snack.expo.io/#flexbox/flatlist-with-state-example
I am having the same issue. I do have a Component that uses FlatList and I would like to know when, within the first render, the list has rendered the visible items (ready state).
I have discovered that on the main component the componentDidMount was triggered because the FlatList component have mounted as well. And because FlatList Component asyncronously renders each item they only show up after on componentDidUpdate.
I have struggled for a while and even with the componentDidUpdate approach I could only get the moment where FlatList got new data (not rendered the items).
So I found out that I could intercept the renderItem method to create some logic to better estimate what and when is being rendered. The other option was to have a setTimeout (very hacky) to trigger the work based on a average time (very poor solution).
If someone have a proper approach to be able to know when the FlatList finishes rendering the inView items please share.
Thanks.

How to handle multiple-button multiple-clicks in react native

I have multiple buttons in a screen and all are independent like one button is for navigating to next page, another one is for a popup calendar, etc. When I click quickly on all these buttons, all clicks are triggered and I tried using disabling the buttons by using a boolean state variable. But still I can click on the button within the time I set the state. So is there any way to prevent this to happen?
Thanks in Advance!
You can easily achieve this behavior by using setState method. However be careful, as set state is asynchronous. For simple scenario you can to do it like this:
constructor(props) {
super(props);
this.state = {
enableButton: false
};
}
And then use your button or TouchableOpacity like this:
<TouchableOpacity
disabled={this.state.enableButton}
onPress={() => handleMe()}>
<Text>
{text}
</Text>
</TouchableOpacity>
And then for enabling your button:
handleMe() {
this.setState({
enableButton: true
});
}
Let me know, if you are still confused.
There might be a issue with function binding. The function might not have been binded which makes them being called even without tap.

react native route flux re-render component on stack pop

How do you re-run React Component Lifecycle methods to determine if a re-render is necessary when transitioning back to previous screens from stack using React Native Router Flux?
Scenario: Scene A -> B -> A
Lets say, A is the initial scene and we navigate from A to B with a push i.e Actions.SceneB. From B to A with a Pop. When the stack is popped to show Scene-A, none of the React Component methods are called for Scene-A. How do I determine if a re-render is necessary? I searched the Issues listed on the github repo and many seems to have this problem without a solution. How is this problem addressed?
I have the ugly work around of calling Actions.refresh() with a setTimeout.
Work Around that works!
This workaround seems to be hacky. There must be a better way to hook into component lifecycle to determine if a re-render is required. Perhaps a callback into the Component?
<TouchableHighlight underlayColor='#efefef' onPress={() => { Actions.pop(); setTimeout(()=> Actions.refresh(), 500)}} style={styles.cancel}>
Options that do not work
Actions.pop({type: 'reset'})
OR
Actions.refresh({"key" : "sceneA"})
Work Around that works! This workaround seems to be hacky. There must be a better way to hook into component lifecycle to determine if a re-render is required.
<TouchableHighlight underlayColor='#efefef' onPress={() => { Actions.pop(); setTimeout(()=> Actions.refresh(), 500)}} style={styles.cancel}>
This will call shouldComponentUpdate() method which gives an option to determine, if a re-render is required.
I was facing the same issue below code gave me required result.
let count = 0;
moveToMainScreen = () => {
count += 1;
Actions.pop({ refresh: { test: count } });
};
<Button onPress={this.moveToMainScreen}> Click </Button>

React Native - seeing stuff load

This might be kinda an awkward question as I am not sure the best way to phrase this..
My React Native app does a decent amount of pulling from a server.. its a social app, sometimes when I load a page in the app that is pulling a decent amount of data from a server you can kinda see stuff loading in.. like almost kinda slowly
Is their a solution to this, maybe a way so it dosen't even render the page until its completely done loading? Or is the solution some sort of loading animation? Any help would be awesome
I believe this is a UX problem and therefore needs a solution such as an activity indicator or overlay with a loading message. Also like Facebook's newsfeed approach, you can display default empty cards so as to make users know that the page is loading.
An easy solution to avoid premature content flashing is to render the content only after fetching is completed. Below is an example component demonstrating this idea.
class YourComponent extends React.Component {
static propTypes = {
fetchData: React.PropTypes.func.isRequired,
}
constructor(props) {
super(props);
this.state = {
dataFetched: false
};
}
async componentDidMount() {
await this.props.fetchData();
this.setState({dataFetched: true});
}
render() {
return (
<View>
{this.state.dataFetched ?
<Text>Fetched</Text> :
null
}
</View>
);
}
}