I am actually starting with Mobile Development and React Native and I thought an interesting Database called Vasern But now I am trying to load things from my database with the componentDidMount() method but i actually just get this Error everytime.
I am sure its just a trivial Error but i just cant find it...
Thanks in Advance
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
TextInput,
Button,
SectionList
} from 'react-native';
import Vasern from 'vasern';
import styles from './styles';
const TestSchema = {
name: "Tests",
props: {
name: "string"
}
}
const VasernDB = new Vasern({
schemas: [TestSchema],
version: 1
})
const { Tests } = VasernDB;
var testList = Tests.data();
class Main extends Component {
state = {
tests: [],
};
constructor(props){
super(props);
this._onPressButton = this._onPressButton.bind(this);
this._onPressPush = this._onPressPush.bind(this);
this._onPressUpdate = this._onPressUpdate.bind(this);
this._onPressDeleteAll = this._onPressDeleteAll.bind(this);
}
componentDidMount() {
Tests.onLoaded(() => this._onPressButton());
Tests.onChange(() => this._onPressButton());
}
_onPressButton = () => {
let tests = Tests.data();
console.log(tests);
//if( tests !== undefined){
this.setState({tests}); // here is the error
//alert(tests);
//}
}
_onPressPush = () => {
Tests.insert({
name: "test"
});
console.log(this.state.tests + "state tests"); //here the console only shows the text
}
_onPressUpdate = () => {
var item1 = Tests.get();
Tests.update(item1.id, {name: "test2"});
}
_onPressDelete = () => {
}
_onPressDeleteAll = () => {
let tests = Tests.data();
tests.forEach((item, i) => {
Tests.remove(item.id)
});
}
_renderHeaderItem({ section }) {
return this._renderItem({ item: section});
}
_renderItem({ item }){
return <View><Text>{item.name}</Text></View>
}
render() {
//const { tests = [] } = this.props;
return (
<View style={styles.container}>
<View>
<TextInput> Placeholder </TextInput>
<Button title="Press me for Show" onPress={this._onPressButton}/>
<Button title="Press me for Push" onPress={this._onPressPush}/>
<Button title="Press me for Update" onPress={this._onPressUpdate}/>
<Button title="Press me for Delete" onPress={this._onPressDelete}/>
<Button title="Press me for Delete All" onPress={this._onPressDeleteAll}/>
</View>
<View style={styles.Input}>
<SectionList
style={styles.list}
sections={this.state.tests}
keyExtractor={item => item.id}
renderSectionHeader={this._renderHeaderItem}
contentInset={{ bottom: 30 }}
ListEmptyComponent={<Text style={styles.note}>List Empty</Text>}
/>
</View>
</View>
);
}
}
export default Main;
Since Tests.data() will return an array (as list of records).
In React Native, you might use FlatList to display an array of records.
import { ..., FlatList } from 'react-native';
...
// replace with SectionList
<FlatList
renderItem={this._renderItem} // item view
data={this.state.tests} // data array
style={styles.list}
keyExtractor={item => item.id}
contentInset={{ bottom: 30 }}
ListEmptyComponent={<Text style={styles.note}>List Empty</Text>}
/>
In case you want to use SectionList, you will need to reform data into sections. Something like:
var sections = [
{title: 'Title1', data: ['item1', 'item2']},
{title: 'Title2', data: ['item3', 'item4']},
{title: 'Title3', data: ['item5', 'item6']},
]
Besides, React Native is in a really good state. I think you will like it.
Related
In my project I have many users and many resources (and many user_resources/the join between users and resources).When I POST to user_resources I see it work on my rails backend (as in I see that instance posted) but in my react native front end I don't see it listed upon update. However, once the app is completely refresh (when I stop and restart the expo server), I finally see those items rendered. ANY IDEAS? I've been working on this forever now to no avail and my project is due tmrw, so any help is appreciated.
screen where I post to user_resources:
import React from 'react';
import { ScrollView,SafeAreaView,StyleSheet, Text, View, FlatList, TouchableOpacity,Button, NativeEventEmitter} from 'react-native';
import {connect} from 'react-redux';
import {fetchResources,searchChanged} from '../actions';
import { addUserResource } from '../actions'
import {SearchBar} from 'react-native-elements';
import { MaterialIcons } from '#expo/vector-icons';
import { MaterialCommunityIcons } from '#expo/vector-icons';
class ResourcesScreen extends React.Component {
state = {
search: ''
}
componentDidMount = () =>{
this.props.fetchResources();
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "lightblue",
}}
/>
);
}
handlePress(item) {
debugger
fetch('http://localhost:3000/user_resources', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({
resource_id: item.id,
user_id: this.props.users.id,
name: item.name,
description:item.description,
link:item.link,
})
})
.then(res => res.json())
.then(data2 => {
console.log(data2)
this.props.addUserResource(data2)
console.log(this.props)
})
}
header = () => {
return <View>
<Text style={styles.header}>Resources</Text>
</View>
}
onSearchChange = text => {
this.setState({search:text})
}
render(){
return(
<SafeAreaView>
<SearchBar placeholderTextColor="white" placeholder="Enter resource name here" onChangeText={this.onSearchChange} value={this.state.search}/>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:this.props.route.params.topicId})} style={styles.buttonitem}>
<Text style={styles.text}>
<MaterialIcons name="add-circle-outline" size={24} color="white"/>Add A New Resource
</Text>
</TouchableOpacity>
<FlatList keyExtractor={(item)=> item.id.toString()} data={this.props.resourceName} ItemSeparatorComponent = { this.FlatListItemSeparator } renderItem={({item}) => {
return <TouchableOpacity style={styles.material2}>
<Text onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:item.id})} style={styles.listitem}>{item.name}</Text>
<MaterialCommunityIcons name="bookmark-plus" size={50} color="#16a085" backgroundColor='black' onPress={()=>this.handlePress(item)}/>
</TouchableOpacity>
}}
ListHeaderComponent = {this.header}/>
</SafeAreaView>
)
}
}
const mapStateToProps = (state) => {
return {
resourceName: state.resourceReducer.resources,
users: state.userReducer,
search:state.resourceReducer.searchTerm
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchResources: () => dispatch(fetchResources()),
addUserResource,
searchChanged
}
}
export default connect(mapStateToProps,mapDispatchToProps)(ResourcesScreen)
After this I head to the profile page where the user_resources SHOULD be displayed, but aren't
import React from 'react';
import { ScrollView,StyleSheet, Text, View, FlatList, TouchableOpacity} from 'react-native';
import {connect} from 'react-redux';
import {SearchBar} from 'react-native-elements';
import { AntDesign } from '#expo/vector-icons';
class Profile extends React.Component{
handleDelete = (id) => {
debugger
fetch(`http://localhost:3000/user_resources/${id}`, {
method: "DELETE",
headers: {
"Authorization": this.props.users.token
}
})
.then(r => r.json())
.then((delResource) => {
console.log(delResource)
this.props.deleteOneFood(delResource)
console.log('deleted')
this.forceUpdate()
})
}
render(){
return(
<View>
{this.props.users.user_resources.map(singleResource=> {
return <Text key={singleResource.id}>{singleResource.name}</Text>
})}
</View>
)}
}
let deleteOneResource = (id) => {
return {
type: "DELETE_ONE_USER_RESOURCE",
payload: id
}
}
const mapDispatchToProps = {
deleteOneResource
}
const mapStateToProps = (state) => {
return {
users: state.userReducer,
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Profile)
I had a flatlist before but thought that may be causing the issues so rendered it another way, still no luck. I tried forceUpdates as well, still no luck. I'm not sure if the issue is coming from my reducer:
let userInitialState = {
id: 0,
username: "",
name: '',
category: '',
token: "",
user_resources:[],
}
let userReducer = (state = userInitialState, action) => {
switch(action.type){
case "ADD_USERS":
let singleNestedObject = {
...action.users.user,
token: action.users.token
}
return {
...state,
username: action.users.user.username,
token: action.users.token,
id: action.users.user.id,
name: action.users.user.name,
category: action.users.user.category,
user_resources: action.users.user.user_resources
}
case "ADD_ONE_USER_RESOURCE":
let copyOfResources = [...state.user_resources, action.userResources]
return {
...state,
user_resources: copyOfResources
}
default:
return state
}
}
and it's action
export const addUserResource = (resourceInfo) => {
return {
type: "ADD_ONE_USER_RESOURCE",
userResources: resourceInfo
}
}
Please help me find the issue here, I'm losing it.
I want implementation app-tour in my project , I installed react-native-app-tour .I have a View that I want assign app-tour to it and I use ref in view that it dispatch AppTourView to inputreducer and finally in useEffect I run appTour but when I run app I encountered Error that error is Tour view does not have React internal Fiber, please can help me
import React, {
useState,
useEffect,
useCallback,
useReducer,
useRef,
} from 'react';
import {AppTour, AppTourSequence, AppTourView} from 'react-native-app-tour';
const inputReducer = (state, action) => {
if (action.type == 'SET_APPTOUR') {
return [...state.appTour, action.data];
}
};
export default function HomeScreen(props) {
const [forsat, setForSat] = useState(null);
const [appTourTargets, dispatchAppTour] = useReducer(inputReducer, {
appTour: [],
});
useEffect(() => {
setTimeout(() => {
console.log(appTourTargets);
let appTourSequence = new AppTourSequence();
appTourTargets.appTour.forEach(appTourTarget => {
appTourSequence.add(appTourTarget);
});
AppTour.ShowSequence(appTourSequence);
}, 1000);
}, [appTourTargets]);
return(
<view style={styles.container}>
<View
ref={useCallback(ref => {
if (!ref) return;
setForSat(ref);
let prop = {
order: 12,
title: 'This is a target View',
description: 'We have the best targets, believe me',
outerCircleColor: '#3f52ae',
cancelable: false,
};
dispatchAppTour({type:'SET_APPTOUR', data:AppTourView.for(ref, {...prop})});
}, [])}
style={styles.rankContainer}>
<BText font="_Light" size={15} color={color.firstColor}>
فرصت{' '}
<BText font="_Bold" color={color.secondColor} size={15}>
{FormatHelper.toPersianString(daysToGo.toString())}
</BText>{' '}
روز تا کنکور
</BText>
</View>
</view>
)
}
I am using Zomato API to get the list of restaurants, data is in the form of the array which has object restaurants in which there are different restaurant objects and then their name and other details.
It's my first time using a flat List and I am not able to display this data.
Goal: Use the search bar to display the list of restaurants in the city using flatlist.
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { FlatList } from 'react-native-gesture-handler';
class Main extends Component {
constructor(props) {
super(props);
this.state = { search: '', data: [] };
}
componentDidMount() {
fetch('https://developers.zomato.com/api/v2.1/search', {
method: 'GET',
headers: {
'user-key': '999999999999999999999999999'
},
params: JSON.stringify({
entity_type: 'city',
q: {this.state.search}
}),
}).then((response) => response.json())
.then((responseJson) => { return this.setState({ data: responseJson.restaurants }) })
.catch((error) => { console.warn(error) }
);
}
render() {
let data = this.state.data;
let name = data.map(p => p.restaurant.name)
console.warn("Check Data", name)
return (
<View>
<SearchBar
round
searchIcon={{ size: 24 }}
placeholder='Search'
onChangeText={search => { this.setState({ search }) }}
value={this.state.search}
/>
//Using this method to display the data if any
{name.length != 0 ?
<FlatList
data={name}
keyExtractor={(x, i) => x + i}
renderItem={({ name }) => <Text>{name}-DATA</Text>}
/>
: <View style={{height:"100%", width:"100%", alignItems:"center",
justifyContent:"center"}}>
<Text>No data found</Text>
</View>
}
</View>
);
}
}
export default Main;
Maybe the way I declared state is wrong, or maybe the way I'm storing the data in the state is wrong.
I got the names of the restaurant in the console.warn successfully.
Without your users-key I can't surely understand what is your api results.
Here
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { FlatList } from 'react-native-gesture-handler';
class Main extends Component {
constructor(props) {
super(props);
this.state = { search: '', data: [] };
}
componentDidMount() {
fetch('http://phplaravel-325095-1114213.cloudwaysapps.com/api/shop/shop/', {
method: 'GET',
}).then((response) => response.json())
.then((responseJson) => { return this.setState({ data: responseJson }) })
.catch((error) => { alert(error) }
);
}
render() {
let data = this.state.data;
return (
<View>
<SearchBar
round
searchIcon={{ size: 24 }}
placeholder='Search'
onChangeText={search => { this.setState({ search }) }}
value={this.state.search}
/>
{data.length != 0 ?
<FlatList
data={data}
keyExtractor={(x, i) => x + i}
renderItem={({ item }) => <Text>{item.name}-DATA</Text>}
/>
: <View style={{height:"100%", width:"100%", alignItems:"center",
justifyContent:"center"}}>
<Text>No data found</Text>
</View>
}
</View>
);
}
}
export default Main;
This is a working code with another api call just add your api call instead on mine.. This is working properly. I guess you are just messing with your data.
Try replacing the renderItem from FlatList to
renderItem={({ item }) => <Text>{item}-DATA</Text>}
Also, replace the condition to use double equals like name.length !== 0
Check the url link properly.
https://developers.zomato.com/api/v2.1/search/999999999999999999999999999
Just check it on web browser it is showing message : The requested url was not found
It means we are not getting any data from this URL.
That why we are not able to map any data.
I am new in react native and looking if someone could direct me in detail how to pass parameters to a child tab.
I researched already and found that it could be done using screenprops, however none of those gave me a clear understanding on how to use it to pass the parameters. A clean sample code could be beneficial.
It is quite easy you have not look around enough there are lots of packages, I recommend you to use following package, and take a look at following example. Next time research information that you need before you ask something.
import React, { Component } from 'react';
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';
import SceneA from './SceneA';
import SceneB from './SceneB';
class Layout extends Component {
constructor(props) {
super(props);
this.state = {
index: 0,
routes: [
{ key: 'active', title: 'Scene A' },
{ key: 'inactive', title: 'Scene B' },
],
};
this.renderScene = this.renderScene.bind(this);
this.renderLabel = this.renderLabel.bind(this);
this.onTabChange = this.onTabChange.bind(this);
}
onTabChange(index) {
this.setState({ index });
}
// Here you can send props to different tab components
renderScene({ route }) {
if (!route.key) return null;
if (route.key === 'active') {
return <SceneA type="active" />; // SceneA specific props here
}
if (route.key === 'inactive') {
return <SceneB type="inactive" />;
}
}
renderLabel({ route }, props) {
const { index } = this.state;
const selected = route.key === props.navigationState.routes[index].key;
return (
<View>
<Text>
{route.title.toUpperCase()}
</Text>
</View>
);
}
renderTab() {
return (
<TabView
navigationState={this.state}
onIndexChange={this.onTabChange}
renderScene={this.renderScene}
renderTabBar={props => (
<TabBar
{...props}
renderLabel={e => this.renderLabel(e, props)}
/>
)}
/>
);
}
render() {
return (
<View>
{this.renderTab()}
</View>
);
}
}
export default Layout;
I am trying out Apollo pagination. It works correctly if I do not pass the limit argument from the client and hard code the limit argument in my hasMoreData function. If I were to add in the limit argument, all the data will be returned from my server and it will not paginate. The server side code should be correct (I tested it on GraphQL playground).
This does not work properly:
import React, { Component } from "react";
import {
View,
Text,
ActivityIndicator,
FlatList,
Button,
StyleSheet
} from "react-native";
import { graphql } from "react-apollo";
import gql from "graphql-tag";
let picturesList = [];
class HomeScreen extends Component {
loadMore = () => {
this.props.data.fetchMore({
variables: {
offset: picturesList.length
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return prev;
}
return {
...prev,
pictures: [...prev.pictures, ...fetchMoreResult.pictures]
};
}
});
};
render() {
const { loading, pictures, variables } = this.props.data;
picturesList = pictures;
if (loading) {
return <ActivityIndicator size="large" />;
}
//TODO - hard coded the limit as 3 which is not supposed to
let hasMoreData = picturesList.length % 3 === 0;
if (picturesList.length <= variables.offset) {
hasMoreData = false;
}
return (
<View style={styles.root}>
<Button title="Show More" onPress={this.loadMore} />
<FlatList
data={picturesList}
renderItem={({ item }) => (
<View style={styles.contentContainer}>
<Text style={styles.content}>{item.title}</Text>
</View>
)}
keyExtractor={item => item.id}
ListFooterComponent={() =>
hasMoreData ? (
<ActivityIndicator size="large" color="blue" />
) : (
<View />
)
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
root: {
flex: 1
},
content: {
fontSize: 35
},
contentContainer: {
padding: 30
}
});
// adding the limit variable here will cause my server to return all data
const PICTURES_QUERY = gql`
query($offset: Int, $limit: Int) {
pictures(offset: $offset, limit: $limit) {
id
title
pictureUrl
}
}
`;
export default graphql(PICTURES_QUERY)(HomeScreen);
The server-side code, just in case:
pictures: async (_, { offset, limit }) => {
let picturesDB = getConnection()
.getRepository(Picture)
.createQueryBuilder("p");
return picturesDB
.take(limit)
.skip(offset)
.getMany();
}
I have added a default parameter in my GraphQL schema:
type Query {
pictures(offset: Int, limit: Int = 3): [Picture!]!
}
Managed to pass the limit variable using Apollo HOC pattern...
export default graphql(PICTURES_QUERY, {
options: () => ({
variables: {
limit: limitAmt
}
})
})(HomeScreen);