I'm new to react native. I am trying to get 'Key' without using the onpress in button.
I just want to get a 'key', when i could open component. How it could be possible?
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
Button,
View,
AsyncStorage
} from 'react-native';
export default class History extends Component {
constructor(props) {
super(props);
this.state = {
myKey: null
}
}
async getKey() {
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({ myKey: value });
} catch (error) {
console.log("Error retrieving data" + error);
}
}
render() {
return (
<View style={styles.container}>
<Button
style={styles.formButton}
onPress={this.getKey.bind(this)}
title="Get Key"
color="#2196f3"
accessibilityLabel="Get Key"
/>
<Text >
Stored key is = {this.state.myKey}
</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
padding: 30,
flex: 1,
backgroundColor: '#F5FCFF',
},
});
I am able to get a key with onpress but i want without onpress. Please suggest.
You can simply get your key value with componentDidMount. As you should know, when the App runs and comes to the current screen, there is a flow of methods will be called before and after rendering the render function. So ComponentDidMount comes after render function is called. So since you need to only display the key value, just follow below code.
constructor(props) {
super(props);
this.state = {
myKey:''
}
}
getKey = async() => {
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({ myKey: value });
} catch (error) {
console.log("Error retrieving data" + error);
}
}
componentDidMount(){
this.getKey();
}
render() {
return (
<View style={styles.container}>
<Button
style={styles.formButton}
onPress={this.getKey.bind(this)}
title="Get Key"
color="#2196f3"
accessibilityLabel="Get Key"
/>
<Text >
Stored key is {this.state.myKey}
</Text>
</View>
)
}
Whenever render function being called, in that time, still key value is not set. So, this.state.myKey would be just Stored key is. But after that, once the componentDidMount called, it sets the myKey value and change states. Which will trig render function to render everything again. That would show your key value within the text component eventually without touching any button.
Related
I am trying to filter out pokemon in my searchbar component however when I type into the search bar the name of the component, nothing happens to the list. I have been searching online for solutions but other examples are too complex to implement into my code. I am consoling.log the input from the search bar component and it logs the input text. But just dont know how to filter out the pokemon. If anyone can help me I will really appreciate it!
// Home.js(Where pokemon ifo is coming from in the componentDidiMount abd then I pass down a function to the searchbar component)
import React, { useState } from "react";
import { View, Text , Button, FlatList, ActivityIndicator, TouchableOpacity } from "react-native";
import { GlobalStyles } from "../styles/GlobalStyles";
import PokeDetails from "./PokeDetails";
import SearchBarComponent from "../components/SearchBar";
import PokeBanner from "../components/PokeBanner";
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
filteredPokemon:[]
}
}
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=27`)
.then((res)=> res.json())
.then((response)=> {
this.setState({
isLoading: false,
dataSource: response.results,
})
console.log("RESPONSE",response)
console.log("RESPONSE.RESSSULTS",response.results)
})
}
filterPokemon =(textToSearch)=> {
const allPokemon = [...this.state.dataSource];
this.setState({
dataSource: allPokemon.filter(pokemon=> pokemon.name.toLowerCase().includes(textToSearch.toLowerCase()))
});
console.log("TextToSearch",textToSearch)
}
render() {
const showIndicator = this.state.isLoading == true ? <ActivityIndicator size="large" color="#0000ff" /> : null;
return(
<View style={GlobalStyles.container}>
<SearchBarComponent filterPoke={this.filteredPokemon} style={GlobalStyles.searchBar}/>
<PokeBanner/>
<View style={GlobalStyles.activityIndicator}>{showIndicator}</View>
<View style={GlobalStyles.pokeFlatList}>
<FlatList
contentContainerStyle={{paddingBottom: 70}}
keyExtractor={(item, index) => item.name}
numColumns={3}
data={this.state.dataSource}
renderItem={({item})=>
<View style={{flex: 1,justifyContent:"center", alignItems:"center", flexDirection: "row", marginBottom: 50, padding: 10}}>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PokeDetails',
{item ,imageUrl: `https://projectpokemon.org/images/normal-sprite/${item.name}.gif`})}>
<PokeDetails imageUrl={`https://projectpokemon.org/images/normal-sprite/${item.name}.gif`} name={item.name}/>
</TouchableOpacity>
</View>
}/>
</View>
</View>
)
}
}
export default Home;
// SearchBarComponent(Where I take the function passed down as a prop and use it in the updateSearch method)
import React from "react";
import {View, StyleSheet } from "react-native";
import { SearchBar } from 'react-native-elements';
import { GlobalStyles } from "../styles/GlobalStyles";
class SearchBarComponent extends React.Component {
state = {
search: '',
};
updateSearch=()=> {
this.props.pokeFilter(this.state.search);
console.log(this.state.search)
}
render() {
const { search } = this.state;
console.log(search)
return (
<View style={GlobalStyles.searchBar}>
<SearchBar
placeholder="Search pokemon..."
onChangeText={text=>this.setState({search: text})}
value={search}
/>
</View>
);
}
}
export default SearchBarComponent;
[![enter image description here][1]][1]
You need to call your updateSearch function when the user wants to search for a pokemon.
There are multiple ways to do that such as you can keep a separate button to handle submit function or call updateSearch inside onChangeText of your search bar component as below,
<SearchBar
placeholder="Search pokemon..."
onChangeText={this.updateSearch}
value={search}
/>
now change your updateSearch to handle serach text
updateSearch = (text) => {
this.setState({ search: text });
this.props.pokeFilter(this.state.search);
}
Also change the props of SearchBarComponent component as (make sure to use correct name)
<SearchBarComponent pokeFilter={this.filterPokemon} style={GlobalStyles.searchBar}/>
But you have to keep a temp variable to store all your pokemons. Because you need to filter data from all pokemons when user midified the search field.
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=27`)
.then((res) => res.json())
.then((response) => {
this.setState({
isLoading: false,
// keep a temp to store all pokemons
pokemons: response.results,
dataSource: response.results,
});
});
}
Now you can use your filter function
filterPokemon = (textToSearch) => {
// load all pokemons from temp
const allPokemon = [...this.state.pokemons];
this.setState({
dataSource: allPokemon.filter(pokemon => pokemon.name.toLowerCase().includes(textToSearch.toLowerCase()))
});
}
Hope this helps you. Feel free for doubts.
You should set FilteredPokemon as all pokemon when you do the first petition and pass that state to the FlatList. That way you will only show the filtered pokemon:
Then when you modify the search you will just filter on the allPokemon state and set it to the filtered. Let me just show it:
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=27`)
.then((res)=> res.json())
.then((response)=> {
this.setState({
isLoading: false,
dataSource: response.results,
filteredPokemon: response.results,
})
console.log("RESPONSE",response)
console.log("RESPONSE.RESSSULTS",response.results)
})
}
filterPokemon =(textToSearch)=> {
const allPokemon = [...this.state.dataSource];
const filteredPokemon = allPokemon.filter((pokemon) =>
pokemon.name.toLowerCase().includes(textToSearch.toLowerCase()))
this.setState({
filteredPokemon
});
console.log("TextToSearch",textToSearch)
}
Any problem just let me know and I will be happy to help!
)
I am programming a Notes App. The Note is saved when navigating back to the homescreen (away from Note Edit Component). The List of the Notes Titles (in HomeScreen) is updated onWillFocus. The Problem is the note save is async and takes some time... so onWillFocus updates the list BEFORE the note is saved. Now i want to call the list update manually when the note save resolves. But I have no idea how to do that.
I have one db file where all database functions live in. And two components.
Now i need to call a function in the HomeScreen Component from the db file.
that is my db file (removed other functions)
//db imports and making a const db
export function updateNote(updateStuff) {
db.get(_id).then(function(doc) {
return db.put({
//updateStuff
});
}).then(async function(response) {
console.log(response)
//here i need to call the function
}).catch(function (err) {
console.log(err);
});
}
and this is my HomeScreen Component
import React from 'react';
import {
//all elements
} from 'react-native';
import { NavigationEvents } from 'react-navigation';
import { putNote, getAllNotes, deleteAllNotes } from './db/db.js';
export default class HomeScreen extends React.Component {
state = {
notes: [],
}
async renderAllNotes() {
let result = await getAllNotes();
this.setState({notes: result.rows});
}
render() {
return (
<View style={styles.container}>
<NavigationEvents
onWillFocus={() => this.renderAllNotes()}
/>
<FlatList
//Flat List Code
/>
</View>
);
}
}
Here is my Note Edit component:
import React from 'react';
import {
//stuff
} from 'react-native';
import { updateNote, getNote, getAllNotes } from './db/db.js';
export default class NoteScreen extends React.Component {
state = {
_id: this.props.navigation.getParam('_id'),
}
updateThisNote() {
updateNote(this.state._id, this.state.title, this.state.content, this.state.createdAt);
}
componentWillUnmount() {
this.updateThisNote();
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ title: text })}
value={this.state.title}
/>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ content: text })}
value={this.state.content}
/>
<Button
title='update Note'
onPress={() => this.updateThisNote()}
/>
</View>
);
}
}
and now renderAllNotes should be calln when updateNote resolves.
I already tried importing the HomeScreen class in the db file and calling the function as well as trying to export the render allNotes function an import it in the db file. Without success ;(
Thank you for every help ;)
EDIT:
async putNoteAndPushRoute() {
let resolve = await putNote("");
this.props.navigation.navigate('Note', {
_id: resolve.id,
renderAllNotes: this.renderAllNotes.bind(this),
});
}
Error Message: _this2.props.renderAllNotes is not a function
You can pass the this.renderAllNotes() to your edit component.
Like this.
...
renderAllNotes(){
....
}
...
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Button onPress={() =>{
navigate('Edit',{
renderAllNotes: this.renderAllNotes.bind(this)
});
}} />
</View>
)
}
...
And then inside your edit,
you can just call the renderAllNotes after the note is updated. But you need to change your updateNote to return a promise
updateThisNote(){
// Make sure your updateNote returns a promise
updateNote(this.state._id, this.state.title,
this.state.content, this.state.createdAt)
.then(() => {
const { params} = this.props.navigation.state;
params.renderAllNotes();
});
}
componentWillUnmount() {
this.updateThisNote();
}
you can change your update function to return a promise
export function updateNote(updateStuff) {
return new Promise(function(resolve, reject) {
db.get(_id).then(function(doc) {
return db.put({
//updateStuff
});
}).then(async function(response) {
console.log(response)
//resolve it here
resolve();
}).catch(function (err) {
console.log(err);
});
}
}
This would solve your issue.
I'm new to react native. I am trying to get 'Key' and 'Key2' with 2 properties myKey' and 'costKey', when calling in TextInput.
The 2 textinput values are saved in async storage keys. Now I am trying to call them with 2 different properties, which are 'myKey' and 'costKey'.
Please suggest, how to get two saved keys with 2 properties when calling.
//AddScreen.js
import React, { Component } from 'react';
import { AppRegistry, AsyncStorage, View, Text, Button, TextInput, StyleSheet, Image, TouchableHighlight, Linking } from 'react-native';
import styles from '../components/styles';
import { createStackNavigator } from 'react-navigation';
import History from '../components/History';
export default class AddScreen extends Component {
constructor(props) {
super(props);
this.state = {
myKey: '',
costKey: '',
text1: '',
text2: '',
}
}
async getKey() {
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
const key = await AsyncStorage.getItem('#MySuperStore:key');
const key1 = await AsyncStorage.getItem('#MySuperStore:key1');
const key2 = await AsyncStorage.getItem('#MySuperStore:key2');
this.setState({ myKey: key }, { costKey: key2 });
} catch (error) {
console.log("Error retrieving data" + error);
}
}
async saveKey(text1, text2) {
key = text1 + text2;
try {
await AsyncStorage.setItem('#MySuperStore:key', key);
await AsyncStorage.setItem('#MySuperStore:key1', text1);
await AsyncStorage.setItem('#MySuperStore:key2', text2);
} catch (error) {
console.log("Error saving data" + error);
}
}
async resetKey() {
try {
await AsyncStorage.removeItem('#MySuperStore:key');
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({ myKey: value }, { costKey: value });
} catch (error) {
console.log("Error resetting data" + error);
}
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.MainContainer}>
<TextInput
style={styles.formInput}
placeholder="Enter key you want to save!"
value={this.state.myKey}
onChangeText={(value) => this.setState({ text1: value })}
/>
<TextInput
style={styles.formInput}
placeholder="Enter key you want to save!"
value={this.state.costKey}
onChangeText={(value) => this.setState({ text2: value })}/>
<Button
onPress={() => this.saveKey(this.state.text1, this.state.text2)}
title="Save key"
/>
<Button
style={styles.formButton}
onPress={this.getKey.bind(this)}
title="Get Key"
color="#2196f3"
accessibilityLabel="Get Key"
/>
<Button
style={styles.formButton}
onPress={this.resetKey.bind(this)}
title="Reset"
color="#f44336"
accessibilityLabel="Reset"
/>
<Text style={styles.instructions}>
Stored key is = {this.state.myKey}
</Text>
<Text style={styles.instructions}>
Stored key is = {this.state.costKey}
</Text>
</View>
)
}
}
Please suggest by taking my example, that how to call two different property separately.
Your request is not so clear, but in a brief analysys I just noticed that you're using setState() incorrectly (both in getKey() and resetKey()). You declared your state as an object with some keys, so you are supposed to modify it passing it a new object with the same structure:
this.setState({
...this.state,
myKey: key,
costKey: key2
});
I am trying to add an array of to my state of beer. What I am looking to accomplish is based on the users choice of favorite beers it adds those specific values on to the state.
the error I am receiving is that 'undefined is not a function' that points to my function to add the state.
import React, { Component } from 'react';
import { View, Text, Picker, StyleSheet } from 'react-native'
class BeerPicker extends Component {
constructor(props){
super(props);
this.state = {
beer: []
};
}
addBeer(newbeer){ <== function throws error
this.setState((state) => {
beer: state.addBeer.push(newbeer)
});
}
render() {
return (
<View>
<Picker selectedValue = {this.state.beer} onValueChange = {this.addBeer}>
<Picker.Item label = "IPA" value = "ipa" />
<Picker.Item label = "Pilsner" value = "pilsner" />
<Picker.Item label = "Stout" value = "stout" />
</Picker>
<Text style = {styles.text}>{this.state.beer}</Text>
</View>
)
}
}
export default BeerPicker;
const styles = StyleSheet.create({
text: {
fontSize: 30,
alignSelf: 'center',
color: 'red'
}
})
Fairly new to React Native so any input would be much accomplished!
The callback to Picker gives you itemValue and itemIndex, you'll have to push this in your beer array and do a bind in constructor
constructor(props){
super(props);
this.state = {
beer: []
};
this.addBeer = this.addBeer.bind(this);
}
addBeer(itemValue, itemIndex){
this.setState((state) => {
beer: [...state.beer, itemValue]
});
}
his problem seems to be context.
try using bind inside your constructor.
this.addBeer = this.addBeer.bind(this);
constructor(props){
super(props);
this.state = {
beer: []
};
this.addBeer = this.addBeer.bind(this);
}
You need to bind addBeer inside your constructor and additionally change your addBeer function to this:
addBeer(newbeer) {
this.setState({
beer: [...this.state.addBeer, newbeer]
});
}
Along with adding this.addBeer = this.addBeer.bind(this) to your constructor...you should also not make it a habit to use a mutator such as .push() in set state.
Try replacing addBeer() with:
addBeer(newbeer){
this.setState({
beer: [...this.state.beer, newbeer]
});
}
I am trying to build a simple login form in React-Native using the tcomb-form-native component. I've created the method handleChange for setting the values to the initial state and the handleForm for submiting. Right now with my code when I'm typing something into the input fields the content is deleted and is replaced with the placeholder (no console output) and when I press the submit button im getting the error "undefined is not an object (evaluating this.refs.form)". Is there a better way how to do it?
Here is how I imported and set up everything:
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
TextInput,
TouchableHighlight,
ActivityIndicator,
Image
} from 'react-native';
var t = require('tcomb-form-native');
var Form = t.form.Form;
var User = t.struct({
username: t.String,
password: t.String
});
var options = {
auto: 'placeholders',
fields: {
password: {
password: true
}
}
};
Here are my class and methods:
class Login extends Component {
constructor(props) {
super(props);
this.state = {
value: {
username: '',
password: ''
},
isLoading: false,
error: false
};
this.handleChange.bind(this);
}
handleChange(value) {
this.setState({value});
}
handleSubmit() {
var value = this.refs.form.getValue();
//update the indicator spinner
this.setState({
isLoading: true
});
console.log(value);
}
And this is how im rendering everything:
render() {
return (
<View style={styles.mainContainer}>
<View style={styles.logo}>
<Image source={require('../icon.png')} />
</View>
<Text style={styles.title}>Login</Text>
<Form
ref={(f) => this.form = f}
type={User}
options={options}
onChangeText={(value) => this.setState({value})}
value={this.state.value}
/>
<TouchableHighlight
style={styles.button}
onPress={this.handleSubmit}
underlayColor="white">
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableHighlight>
</View>
);
}
Don't Use Bind When Passing Props
then you can do like this
onPress={this.handleSubmit}
handleSubmit = () => {...}
In TouchableHightlight, you need to define: onPress={this.handleSubmit} as:
onPress={() => this.handleSubmit()} or
onPress={this.handleSubmit.bind(this)}
In addition, ref should not be string nowadays in React (+ Native) (https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute), but e.g.:
ref={(f) => this.form = f}
and then you refer to it with this.form.