How to call a functional component in a class component? - react-native

I have a functional component to check if fonts have been loaded or not, I want to call it before the app render in App.js and if it's loaded give it a state called loaded but i don't know how can I do that because it's a class component, it's quite confusing to me:
Here's the functional component code:
export default function Cache() {
const [isLoadingComplete, setLoadingComplete] = React.useState(false);
React.useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
SplashScreen.preventAutoHideAsync();
await Font.loadAsync({
/// fonts
});
finally {
setLoadingComplete(true);
SplashScreen.hideAsync();
}
}
loadResourcesAndDataAsync();
}, []);
return isLoadingComplete;
}
And here's my app.js component in which I want to call the Cache component:
export class App extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
};
}
componentDidMount() {
firebase.auth().onAuthStateChanged((user) => {
if (!user) {
this.setState({
loggedIn: false,
});
} else {
this.setState({
loggedIn: true,
});
}
});
}
render() {
const { loggedIn, loaded } = this.state;
if (!loaded) {
return null;
} else {}

You can just put your fonts in the componentDidMount like that
async componentDidMount(){
await Font.loadAsync({
'Montserrat': require('../assets/fonts/Montserrat.ttf'),
}).then(() => {
this.setState({fontLoaded: true})
})

Related

Why is InterstitialAd not loaded after the first trigger?

I manage to get the first ad to show, but app crashed the next time I try to trigger an ad. And gives me this error: Error: InterstitialAd.show() The requested InterstitialAd has not loaded and could not be shown
In App.js
componentDidMount() {
const eventListener = interstitial.onAdEvent(type => {
if (type === AdEventType.LOADED) {
this.setState({
setLoaded: true,
});
}
});
interstitial.load();
eventListener();
}
showAds = () => {
interstitial.show();
// No advert ready to show yet
if (!this.state.loaded) {
console.log('null');
return null;
}
};
// This trigger is within another function
this.showAds();
I have a class component so I use ComponentDidMount instead of useEffect. Might that cause some troubles?
UPDATE:
this.state = {
loaded: false,
setLoaded: false,
Listener: null,
};
The above state is an attempt to redo
const [loaded, setLoaded] = useState(false);
constructor () {
super();
this.Listener=null
}
componentDidMount() {
this.Listener = interstitial.onAdEvent(type => {
if (type === AdEventType.LOADED) {
this.setState({
loaded: true,
});
}else if(type === AdEventType.CLOSED){
this.loadAd()
}
});
this.loadAd()
}
componentWillUnmount(){
if(this.Listener!==null){
this.Listener()
}
}
loadAd = () =>{
this.setState({
loaded: false,
});
interstitial.load();
}
showAds = () => {
if (!this.state.loaded) {
console.log('null');
return null;
}else{
interstitial.show();
}
};

Update points Redux React Native

I'm trying to load points from Firebase in order to display it on the screen
I'm using Redux, because the points number can be updated but I can not put this.props.Points.updatePoint inside Firebase request
How can I update it?
Home.js :
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount = async () => {
const pointsRef=firebase.database().ref("Users").child(firebase.auth().currentUser.uid).orderByChild("Points").once('value',function(snapshot){
const Points=snapshot.val().Points
});
this.props.Points.updatePoints(Points)
render(){
return(
<Text>{this.props.Points}</Text>
)}
}
const mapStateToProps = (state) => {
return {
Points:state.Points};
};
const mapDispatchToProps = (dispatch) => {
return {
updatePoints:(Points)=>dispatch({ type: "UPDATE_POINTS", payload: Points }),
};
};
PointReducer.js :
const initialState = {
Points: 0,
};
const Points = (state = initialState, action) => {
switch (action.type) {
case "UPDATE_POINTS":
return {
...state,
Points: action.payload,
};
default:
return state;
}
};
export default Points;
Your method is correct. The problem is actually with the way you're trying to access to updatePoints function in mapDispatchToProps & the place you're run the statement.
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount = async () => {
const pointsRef = firebase
.database()
.ref("Users")
.child(firebase.auth().currentUser.uid)
.orderByChild("Points")
.once("value", (snapshot) => {
const Points = snapshot.val().Points;
this.props.updatePoints(Points); // You can directly access to `updatePoints` using prop object.
}); // convert this function to an arrow function. It will fix `this` related issues.
};
render() {
return <Text>{this.props.Points}</Text>;
}
}
const mapStateToProps = (state) => {
return {
Points: state.Points,
};
};
const mapDispatchToProps = (dispatch) => {
return {
updatePoints: (Points) =>
dispatch({ type: "UPDATE_POINTS", payload: Points }),
};
};
Let me know if you need further support.

Calling componentWillMount every time focused page in react native

I want call the componentWillMount every time that I focused a page. I using react-redux and react-navigation.
With react-navigation I use import { withNavigationFocus } from 'react-navigation'; to detect if the page was active but when I call componentDidMount there ara a few seconds that I see old view. Is for this I want calling componentWillMount instead of componentDidMount when page focused.
This is my code:
class HomeScreen extends React.Component {
componentWillMount() {
this.props._loading(true);
}
omponentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener('didFocus', () => {
this.setState({loading: 0});
this.props._loading(true);
Api.get('s?type=Featured')
.then( response => {
if (response.profiles){
this.setState({featured_users: response.profiles, loading: this.state.loading + 1});
}
}).catch((error) => {
console.log(error);
this.props._loading(false);
});
Api.get('s?type=Top')
.then( response => {
if (response.profiles){
this.setState({featured_top: response.profiles, loading: this.state.loading + 1});
}
}).catch((error) => {
console.log(error);
this.props._loading(false);
});
});
}
componentWillUnmount() {
// Remove the event listener
this.focusListener.remove();
}
render() {
if (this.state.loading >= 4){
this.props._loading(false);
}
return (
...
);
}
}
const mapStateToProps = (state) => ({
user: state.reducerUser,
loading: state.reducerGeneral
});
mapDispatchToProps = dispatch => {
return {
_loading: loading => {
dispatch(actionLoading(loading));
},
updateUser: user => {
dispatch(actionUser(user));
},
}
}
export default withNavigationFocus(connect(mapStateToProps, mapDispatchToProps)(HomeScreen));
You can add this inside your componentWillMount and whatever you write inside your addListener , it will be executed everytime:
this.focusListener = this.props.navigation.addListener('didFocus', () => {
// The screen is focused
this.getData();
});

optimistic update for like/dislike and like count with react native, redux

I am building simple video with like/dislike capability like
this
but its not working properly when like or dislike rejected because in componentDidUpdate its going to loop and I dont know what condition should I use to prevent from that.
This is my component:
class PlayingVideo extends Component {
constructor(props) {
super(props);
this.state = {
likedThis: _.includes(this.props.video.likedBy, this.props.user_id),
likedLength: this.props.video.likedBy.length
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.likeVideoHasError) {
this.setState({
likedThis: false,
likedLength: this.state.likedLength - 1
});
}
if (this.props.dislikeVideoHasError) {
this.setState({
likedThis: true,
ikedLength: this.state.likedLength + 1
});
}
}
like = () => {
if (this.props.likeVideoPending || this.props.dislikeVideoPending) return;
this.setState({ likedThis: true, likedLength: this.state.likedLength + 1 });
this.props.dispatch(likeVideo(this.props.videoId));
};
dislike = () => {
if (this.props.likeVideoPending || this.props.dislikeVideoPending) return;
this.setState({
likedThis: false,
likedLength: this.state.likedLength - 1
});
this.props.dispatch(dislikeVideo(this.props.videoId));
};
}
const mapStateToProps = (state, ownProps) => {
return {
likeVideoHasError: state.video.likeVideoHasError,
dislikeVideoHasError: state.video.dislikeVideoHasError,
likeVideoPending: state.video.likeVideoPending,
dislikeVideoPending: state.video.dislikeVideoPending
};
};
export default connect(mapStateToProps)(PlayingVideo);

Use a global alert across the react-native app

I'm a beginner for react-native and I need to alert to the user based on a status which will be retrieved from an API in every 15 seconds. For this I'm using react-native-background-timer in my main component to call the service. But when app is in some other screen (component) even though the service executes perfectly in the main component, it doesn't update it's props or status depending on the result it received (I guess this should be because I'm in a some other screen and props of main component will not be updated). Due to that alert will not be triggered if app is not in the main component
Can anyone please suggest me an approach for this?
class Home extends Component{
constructor(props){
super(props)
this._onPopUpShowed = this._onPopUpShowed.bind(this)
}
componentDidMount(){
//Initial call after the launch
this.props.fetchLiveOrderData()
//Start timer for polling
const intervalId = BackgroundTimer.setInterval(() => {
isBackgroudLoad=true
this.props.fetchLiveOrderData()
}, 1000*15);
}
render(){
const{payload,isFetching,isError,isSuccess} = this.props.liveOrderData
return(
//Render UI depending on the data fetched
);
}
}
//map state to props
const mapStateToProps = state => {
return {
liveOrderData: state.liveOrderData
}
}
//map dispatch to props
const mapDispatchToProps = dispatch => {
return {
fetchLiveOrderData : () => dispatch(fetchLiveOrderData())
}
}
export default connect(mapStateToProps, mapDispatchToProps) (Home)
liveOrderReducer.js
import {
FETCHING_LIVE_ORDER_DATA, FETCHING_LIVE_ORDER_DATA_SUCCESS, FETCHING_LIVE_ORDER_DATA_ERROR
} from '../constants'
const initialState = {
payload: [],
msg:[],
isFetching: true,
isError: false,
isSuccess: false
}
export default liveOrderReducer = (state = initialState, action) => {
switch(action.type){
case FETCHING_LIVE_ORDER_DATA :
return {
...state,
payload: [],
msg:[],
isFetching: true,
isError: false,
isSuccess: false
}
case FETCHING_LIVE_ORDER_DATA_SUCCESS :
return {
...state,
payload: action.data,
msg:[],
isFetching: false,
isError: false,
isSuccess:true
}
case FETCHING_LIVE_ORDER_DATA_ERROR :
return {
...state,
payload: [],
msg:action.msg,
isFetching: false,
isError: true,
isSuccess:false
}
default:
return state
}
}
index.js
import {
FETCHING_LIVE_ORDER_DATA, FETCHING_LIVE_ORDER_DATA_SUCCESS, FETCHING_LIVE_ORDER_DATA_ERROR
} from '../constants'
import api from '../lib/api'
export const getLiveOrderData = () => {
return {
type : FETCHING_LIVE_ORDER_DATA
}
}
export const getLiveOrderDataSuccess = data => {
return {
type : FETCHING_LIVE_ORDER_DATA_SUCCESS,
data
}
}
export const getLiveOrderDataFailure = () => {
return {
type : FETCHING_LIVE_ORDER_DATA_ERROR
}
}
export const fetchLiveOrderData = () => {
return(dispatch) => {
dispatch(getLiveOrderData())
api.getOrder().then(resp => {
dispatch(getLiveOrderDataSuccess(resp))
}).catch((err) => {
dispatch(getLiveOrderDataFailure(err))
})
}
}
Move the notification code to the container or the root component. This will ensure you will receive notifications even if the user moved away from the home screen.