I need to access the navigate prop in a class component to navigate to another page however that's not possible outside a functional component. And I'm having trouble trying to use the workaround from the docs.
Current code is just returning an error
I have a feeling I am just misunderstanding the docs in this case. Any help would be huge!
Class Component
import { firebase } from "#react-native-firebase/auth";
import { NavigationContainer, useNavigation } from "#react-navigation/native";
import {
Box,
Button,
Divider,
HStack,
Heading,
ScrollView,
Spinner,
Text,
} from "native-base";
import React from "react";
const user = firebase.auth().currentUser;
function getIsQuestCompleted(querySnapshot: any) {
return querySnapshot.get("key");
}
class TaskTrackingComp extends React.Component {
state = {
savedKey: [],
ttrkerData: [],
loading: true,
};
getTarkovTrackerData = async () => {
await fetch("https://tarkovtracker.io/api/v2/progress", {
method: "GET",
headers: {
Authorization: `Bearer ${this.state.savedKey}`,
},
})
.then((res) => res.json())
.then((data) =>
this.setState({
ttrkerData: data,
loading: false,
})
);
};
componentDidMount() {
firebase
.firestore()
.collection("UserApiKeys")
.doc(user?.uid)
.get()
.then((querySnapshot) => getIsQuestCompleted(querySnapshot))
.then((savedKey) => {
console.log("Saved Key", savedKey),
this.setState({
savedKey,
}),
this.getTarkovTrackerData();
});
}
render() {
const { navigation } = this.props;
console.log("savedKey state:", this.state.savedKey);
console.log("Tarkov Tracker Data state:", this.state.ttrkerData);
console.log("Loading?", this.state.loading);
return (
<ScrollView>
<Box justifyContent={"center"} alignItems={"center"}>
<Heading fontWeight={"extrabold"}>Tarkov Tracker Stats</Heading>
</Box>
<Divider />
{this.state.loading ? (
<HStack space={2} justifyContent={"center"} alignItems={"center"}>
<Box>
<Text>Getting Stats</Text>
</Box>
<Box>
<Spinner color="warning.500" />
</Box>
</HStack>
) : (
<Box justifyContent={"center"} alignItems={"center"}>
<Button onPress={() => navigation.navigation("Home")}></Button>
</Box>
)}
</ScrollView>
);
}
}
export default function TaskTracking(props: any) {
const navigation = useNavigation();
return <TaskTrackingComp {...props} navigation={navigation} />;
}
This was a mistake on my part I did not realise the export was a default and that was causing the error!
try changing onPress function of Button to this navigation.navigate("Home")
Related
Now I have created this custom hook to perform lazy loading,which takes redux slice action as input and
import { useState, useEffect, useCallback, useRef } from "react";
import { useDispatch } from "react-redux";
function useLazyFetch(fetchAction) {
const dispatch = useDispatch();
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const loadMoreRef = useRef(null);
const handleObserver = useCallback(async(entries) => {
const [target] = entries;
console.log(target.isIntersecting);
if (target.isIntersecting) {
console.log("INTERSECTING.....");
await new Promise((r) => setTimeout(r, 2000));
setPage((prev) => prev + 1);
}
}, []);
useEffect(() => {
const option = {
root: null,
rootMargin: "0px",
threshold: 1.0,
};
const observer = new IntersectionObserver(handleObserver, option);
if (loadMoreRef.current) observer.observe(loadMoreRef.current);
}, [handleObserver]);
const fetchApi = useCallback(async () => {
try {
setLoading(true);
await new Promise((r) => setTimeout(r, 2000));
dispatch(fetchAction(page))
setLoading(false);
} catch (err) {
console.error(err);
}
}, [page,fetchAction,dispatch]);
useEffect(() => {
fetchApi();
}, [fetchApi]);
return { loading, loadMoreRef };
}
export default useLazyFetch;
I am using this in my component like this, here you can see I am tracking div in the bottom using loadMoreRef from useLazyFetch, Now when I am commenting out the fetchApi(); from custom hook its working as expected, on scroll its logging INTERSECTING... in the console but the moment I try to execute the action through fetchApi() my whole app goes into loop,the div tracker with ref comes to top and it fetches the posts but after immediately that action repeats the tracker comes to top and page becomes empty & it fetches next set of posts,I can see that my list is getting appended new set of posts to state in redux dev tool instead of completely setting new state, but in UI it's rendering all posts again and again whic is causing the loop,how can I avoid this ?
import { CircularProgress, Grid, IconButton, Typography } from "#mui/material";
import { Box } from "#mui/system";
import React, { useEffect,useRef,useState } from "react";
import AssistantIcon from "#mui/icons-material/Assistant";
import Post from "../components/Post";
import { useDispatch, useSelector } from "react-redux";
import { getPosts } from "../redux/postSlice";
import AddPost from "../components/AddPost";
import useLazyFetch from "../hooks/useLazyFetch";
export default function Home() {
const dispatch = useDispatch();
// const api = `https://picsum.photos/v2/list`
const { status, posts } = useSelector((state) => state.post);
const {loading,loadMoreRef} = useLazyFetch(getPosts)
useEffect(() => {
dispatch(getPosts());
}, []);
return (
<Box>
<Box borderBottom="1px solid #ccc" padding="8px 20px">
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Typography variant="h6">Home</Typography>
</Grid>
<Grid item>
<IconButton>
<AssistantIcon />
</IconButton>
</Grid>
</Grid>
</Box>
<Box height="92vh" sx={{ overflowY: "scroll" }}>
<AddPost />
<Box textAlign="center" marginTop="1rem">
{status === "loading" && (
<CircularProgress size={20} color="primary" />
)}
</Box>
{status === "success" &&
posts?.map((post) => <Post key={post._id} post={post} />)}
<div style={{height:"50px",width:"100px",backgroundColor:"red"}} ref={loadMoreRef}>{loading && <p>loading...</p>}</div>
</Box>
</Box>
);
}
And here is my redux action & state update part
const initialState = {
status: "idle",
posts: []
};
export const getPosts = createAsyncThunk("post/getPosts", async (page) => {
console.log(page);
console.log("calling api ...");
const { data } = await axios.get(`/api/posts?page=${page}`);
return data;
});
export const postSlice = createSlice({
name: "post",
initialState,
reducers: {},
extraReducers: {
[getPosts.pending]: (state, action) => {
state.status = "loading";
},
[getPosts.fulfilled]: (state, action) => {
state.status = "success";
state.posts = [...state.posts,...action.payload.response.posts] ;
},
[getPosts.rejected]: (state, action) => {
state.status = "failed";
},
}
this is the solution that is working
import { CircularProgress, Grid, IconButton, Typography } from "#mui/material";
import { Box } from "#mui/system";
import React, { useEffect,useMemo } from "react";
import AssistantIcon from "#mui/icons-material/Assistant";
import Post from "../components/Post";
import { useDispatch, useSelector } from "react-redux";
import { getPosts } from "../redux/postSlice";
import AddPost from "../components/AddPost";
import useLazyFetch from "../hooks/useLazyFetch";
export default function Home() {
const { status, posts } = useSelector((state) => state.post);
const {loading,loadMoreRef} = useLazyFetch(getPosts)
const renderedPostList = useMemo(() => (
posts.map((post) => {
return( <Post key={post._id.toString()} post={post} />)
})
), [posts])
return (
<Box>
<Box borderBottom="1px solid #ccc" padding="8px 20px">
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Typography variant="h6">Home</Typography>
</Grid>
<Grid item>
<IconButton>
<AssistantIcon />
</IconButton>
</Grid>
</Grid>
</Box>
<Box height="92vh" sx={{ overflowY: "scroll" }}>
<AddPost />
<Box textAlign="center" marginTop="1rem">
{status === "loading" && (
<CircularProgress size={20} color="primary" />
)}
</Box>
{renderedPostList}
<div style={{height:"50px",width:"100px",backgroundColor:"red"}} ref={loadMoreRef}>{loading && <p>loading...</p>}</div>
</Box>
</Box>
);
}
}
I used useMemo hook to memoize and it works as expected
I'm trying to display a flat list (values form json placeholder) filterable with a search bar and it's not rendering for some reason. The values are not visible. Thanks!
The flat list code:
import React, { Component } from "react";
import { View, Text, FlatList, Button } from "react-native";
import { ListItem, SearchBar } from "react-native-elements";
class FlatListDemo extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
temp: [],
error: null,
search: null
};
}
componentDidMount() {
this.getData();
}
getData = async () => {
const url = `https://jsonplaceholder.typicode.com/users`;
this.setState({ loading: true });
try {
const response = await fetch(url);
const json = await response.json();
this.setResult(json);
} catch (e) {
this.setState({ error: 'Error Loading content', loading: false });
}
};
setResult = (res) => {
this.setState({
data: [...this.state.data, ...res],
temp: [...this.state.temp, ...res],
error: res.error || null,
loading: false
});
}
renderHeader = () => {
return <SearchBar placeholder="Search Here..."
lightTheme round editable={true}
value={this.state.search}
onChangeText={this.updateSearch} />;
};
updateSearch = search => {
this.setState({ search }, () => {
if ('' == search) {
this.setState({
data: [...this.state.temp]
});
return;
}
this.state.data = this.state.temp.filter(function(item){
return item.name.includes(search);
}).map(function({id, name, email}){
return {id, name, email};
});
});
};
render() {
return (
this.state.error != null ?
<View style={{flexDirection: 'column',justifyContent: 'center', alignItems: 'center' }}>
<Text>{this.state.error}</Text>
<Button onPress={
() => {
this.getData();
}
} title="Reload" />
</View> :
<FlatList
ListHeaderComponent={this.renderHeader}
data={this.state.data}
keyExtractor={item => item.email}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name}`}
subtitle={item.email}
/>
)}
/>
);
}
}
export default FlatListDemo;
Importing this list to:
import React, {useState, useEffect} from 'react'
import { Text, View, StyleSheet, StatusBar, SafeAreaView } from "react-native"
import "firebase/auth";
import 'react-native-gesture-handler';
import "firebase/auth";
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import FlatListDemo from './FlatListDemo';
const Home: () => React$Node = () => {
return(
<>
<StatusBar barStyle="dark-content"/>
<SafeAreaView style={{flex: 1}}>
<FlatListDemo/>
</SafeAreaView>
</>
);
};
export default Home;
This is what it looks like (values should be there). Using Expo on Android:
photo1
Thanks! I appreciate the help!
It seems to me that you are using a ListElement as it is defined in version 1.2.0 of react-native-elements but the actual version that you are using is > 1.2.0.
You are implementing it similar to the documentation of react-native-elements 1.2.0.
However, the definition of ListItem has changed in newer version. In the newest version, the ListItem component is just a simple view wrapper. Hence, it needs to contain children in order to display the information that you want.
In your case this could be implemented as follows (I did not know what roundAvatar is doing).
renderItem={({ item }) => (
<ListItem>
<ListItem.Content>
<ListItem.Title>{`${item.name}`}</ListItem.Title>
<ListItem.Subtitle>{item.email}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
Check the documentation of the newest version for the exact features that you want to use.
I suspect I'm having a problem with my onSubmit function.
The error stated above is what I encounter when I run the application.
I have tried to change my onSubmit function to take "title" as the payload, but that too did not work
Assistance would greatly be appreciated.
addAuctionForm:
import React, {Component} from 'react'
import { TextInput, Button } from 'react-native-paper'
import { View } from 'react-native'
import { connect} from 'react-redux'
import { Formik } from 'formik'
import { addAuction} from '../../actions/index'
function mapDispatchToProps(dispatch) {
return {
addAuction: auction => dispatch(addAuction(auction))
}
}
class ConnectedForm extends Component {
constructor(props) {
super(props)
this.state = {
title: ''
}
}
render() {
return (
<Formik
onSubmit={() => addAuction(auction)}
>
{({ handleChange, handleSubmit, values}) => (
<View>
<TextInput
onChangeText={handleChange('title')}
value={auction.title}
/>
<Button onPress={handleSubmit} title="SUBMIT"/>
</View>
)}
</Formik>
);
}
}
const Form = connect(null, mapDispatchToProps)(ConnectedForm)
export default Form
action:
import { ADD_AUCTION } from '../constants/action-types'
export function addAuction(payload) {
return { type: 'ADD_AUCTION', payload}
}
reducer:
import {ADD_AUCTION} from '../constants/action-types';
const initialState = {
auctions: []
}
function rootReducer(state = initialState, action) {
if (action.type === ADD_AUCTION) {
return Object.assign({}, state, {
auctions: state.auctions.concat(action.payload)
})
}
return state
}
export default rootReducer;
The lib you are using (react-native-paper) and Formik are not directly compatible. You won't be able to use the handle* props directly.
Your best bet is to use setFieldValue and submitForm directly:
<Formik
onSubmit={() => addAuction(auction)}
>
{({ setFieldValue, submitForm, values}) => (
<View>
<TextInput
onChangeText={v => setFieldValue('title', v)}
value={auction.title}
/>
<Button onPress={() => submitForm()} title="SUBMIT"/>
</View>
)}
</Formik>
I'm trying to learn, react us and try to load the API on my pokedex app. https://pokeapi.co/api/v2/pokedex/1/ I'm trying to load every pokemon on the ( pokemon_entries ) list, but I don't know how to do
I have already created the card of the different Pokemon and I had tried to load the List on my app
ListPokemon
import React from 'react';
import Loader from '../components/Loader';
class ListPokemon extends React.Component {
state = {
isLoading: false,
data: [ ]
};
async componentDidMount() {
this.setState({isLoading:true})
const {name, url} = this.props;
try {
const response = await fetch(`https://pokeapi.co/api/v2/pokedex/1/`);
const json = await response.json();
this.setState({data: json,isLoading:false})
console.log({json})
} catch (err){
console.log(err.msg);
this.setState({isLoading:false})
throw err
}
}
render() {
const {isLoading,data} = this.state;
return (
<>
<h1>Lorem</h1>
{
isLoading ?<Loader/> : <h1>{data.entry_number}</h1>
}
</>
);
}
}
export default ListPokemon
DataPokemon :
import React from 'react';
import { Card,Container,Row,Col } from 'react-bootstrap';
const DataPokemon = props => {const { name } = props;
return(
<Container>
<Row>
<Col xs={6}>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>{name}</Card.Title>
<Card.Text>
</Card.Text>
{/* <Button variant="primary">Go somewhere</Button> */}
</Card.Body>
</Card>
</Col>
</Row>
</Container>
)
}
export default DataPokemon;
Thank you !
You can change the x and get more or less pokemons.
const pokeArray = [];
for(let i=1; i<x; i++) {
axios.get(`https://pokeapi.co/api/v2/pokemon/${i}`).then(res => {
pokeArray.push( {
id: i,
name: res.data.name,
photo: res.data['sprites']['front_default'],
hp: res.data['stats'][5]['base_stat'],
attack: res.data['stats'][4]['base_stat'],
defense : res.data['stats'][3]['base_stat'],
} )
})
}
I'm working on a very simple react-native app where I type the name of an artist in a searchbox, retrieve a list of artists from the spotify API and I display this list in FlatList component.
I manage to get the list of artists and I want to save it in the local state so that I pass it to the FlatList component.
The list object looks like this : [{...}, {...}, {...}, {...}]
But it doesn't seem to work and I think that my state is not updating and I don't know what I'm doing wrong.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
FlatList,
StatusBar,
TextInput,
} from 'react-native';
import colors from './utils/colors';
import { List, ListItem, SearchBar } from 'react-native-elements';
import { searchArtist } from './utils/fetcher';
import { debounce } from 'lodash';
export default class spotilist extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
query: '',
artists: [],
error: null,
refreshing: false,
};
}
render() {
return (
<View style={ styles.container }>
<StatusBar barStyle="light-content" />
<TextInput style={ styles.searchBox }
value={this.state.value}
onChangeText={ this.makeQuery }
/>
<List>
<FlatList
data={this.state.artists}
//renderItem={({item}) => <Text>{item.name}</Text>}
/>
</List>
// {
// this.state.artists.map(artist => {
// return (
// <Text key={artist.id}>{artist.name}</Text>
// )
// })
// }
</View>
);
}
makeQuery = debounce(query => {
searchArtist(query)
.then((artists) => {
console.log(artists); // I have the list
this.setState({
artists: this.state.artists,
});
})
.catch((error) => {
throw error;
});
}, 400);
}
Thank you for your help.
UPDATE
I also tried using this without success :
<List>
<FlatList
data={this.state.artists}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={item.name}
avatar={{ uri: item.images[0].url }}
/>
)}
/>
</List>
In the makeQuery function you need to set the response from the server like..
makeQuery = debounce(query => {
searchArtist(query)
.then((artists) => {
console.log(artists); // I have the list
this.setState({
artists: artists, //Here is the change
});
})
.catch((error) => {
throw error;
});
}, 400);