Child component inside modal unexpectedly resets to default state, React Native - javascript

I have a parent component--LeagueSelect--and a child component TeamSelect.
LeagueSelect is a React Native modal.
When I open LeagueSelect, make adjustments in the LeagueSelect modal, collapse the modal, and open it again, the state changes are preserved.
If I open LeagueSelect, make adjustments to TeamSelect in the LeagueSelect modal, collapse the modal, and open it again, the state changes are not preserved.
To provide context, when the modal (LeagueSelect) is open, this is what it looks like; the first red box is part of LeagueSelect, and the second red box is part of TeamSelect:
This is my LeagueSelect component; I think the issue is happening in setModalVisible, because the console logs read the correct state when I console.log the state on componentWillUnmount:
class LeagueSelect extends Component {
constructor(props) {
super(props)
this.state = {
modalVisible: false,
checked: [],
checkedLeagues: [],
uncheckedLeagues: [],
checkMessage: '',
firstString: []
}
}
setModalVisible(visible) {
this.setState({modalVisible: visible})
if(this.state.checked.length === 0) {
this.props.league.map(
(v, i) => {
this.state.checked.push(true)
this.state.checkedLeagues.push(v.acronym)
}
)
}
this.setState({ checkMessage: '' })
matchedTeams = []
if(undefined !== this.props.teamObject) {
this.props.teamObject.map(
(v, i) => {
if(this.state.checkedLeagues.includes(v.league.acronym)){
matchedTeams.push(v.team_name)
}
}
)
}
queryString = []
//encodes the teams that have their leagues selected
matchedTeams.map(
(v, i) => {
if (queryString.length < 1) {
queryString.push(`?team=${v}`)
} else if (queryString.length >= 1 ) {
queryString.push(`&team=${v}`)
}
}
)
queryString = queryString !== undefined ? queryString.join('') : ''
axios.get(`http://localhost:4000/reports${queryString}`)
.then(response => {
this.props.loadCards(response.data)
})
}
componentDidMount() {
this.props.loadLeagues()
this.props.loadTeams()
}
componentDidUpdate(){
console.log(this.props.checkedLeagues)
console.log('in league - in update - checked Teams', this.props.checkedTeams)
this.props.changeLeagues(this.props.league, this.state.checkedLeagues, this.props.checkedTeams, this.props.queryTeams, this.props.teamObject)
}
render(){
return (
<View style={{ position: 'relative'}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}
>
<View
style={{
marginTop: 100
}}
>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}
>
<Image
source={require('../assets/exit.png')}
style={{
height: 20,
width: 20,
left: 320,
resizeMode: 'contain'
}}
/>
</TouchableHighlight>
<Text
style={{
paddingTop: 8,
paddingLeft: 5,
fontSize: 15,
fontFamily: 'Helvetica',
fontSize: 13
}}
>LEAGUE SELECT</Text>
<View
style={{
flexDirection:"row",
paddingLeft: 10
}}
>
{this.props.league === null ?'' : this.props.league.map(
(v, i) => {
return(
<View
key={i}
style={{
alignSelf: 'flex-end',
flexDirection:"row",
top: 4,
paddingRight: 10
}}
>
<Check
checked={this.state.checked[i]}
index={i}
value={v.acronym}
changeCheck={this.changeCheck}
style={{
paddingRight: 10
}}
/>
</View>
)
}
)}
</View>
<Text
style={{
paddingLeft: 10,
paddingTop: 12,
fontStyle: 'italic',
color: '#F4AF0D'
}}
>{this.state.checkMessage}</Text>
<TeamSelect />
</View>
</Modal>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Icon
style={{
position: 'absolute',
top: -34,
right: 10,
fontSize: 25,
color: 'grey'
}}
name='settings'
/>
</TouchableHighlight>
</View>
);
}
}
function mapStateToProps(state) {
return {
league: state.league.league,
team: state.team.team,
checkedLeagues: state.league.checkedLeagues,
checkedTeams: state.league.checkedTeams,
queryTeams: state.league.queryTeams,
teamObject: state.league.teamObject
}
}
export default connect(mapStateToProps, { loadCards, loadLeagues, loadTeams, changeLeagues })(LeagueSelect)
This is the TeamSelect component where the second red box's selections are made:
class TeamSelect extends Component {
constructor(props) {
super(props)
this.state = {
checked: [],
checkedTeams: [],
teamObject: [],
queryString: [],
accordionStatus: [true, true, true]
}
}
componentDidMount(){
console.log('did mount - checked Teams State', this.state.checkedTeams)
//updates checked teams on load
if(this.state.count === false && this.state.checkedTeams.length === 0 && this.state.checked.length === 0){
this.setState({ count: true})
this.props.team.map(
(v, i) => {
if(this.props.checkedLeagues.includes(v.league.acronym)) {
this.state.checked.push(true)
this.state.checkedTeams.push(v.team_name)
this.state.teamObject.push(v)
} else if (this.state.checkedTeams !== undefined) {
this.state.checked.push(false)
}
}
)
this.forceUpdate()
}
}
componentWillUnmount(){console.log("unmount - count", this.state.count)
console.log('will unmount - checked Teams State', this.state.checkedTeams)
}
componentDidUpdate(){
this.props.changeLeagues(this.props.league, this.props.checkedLeagues, this.state.checkedTeams, this.state.queryString, this.state.teamObject)
}
changeCheck = (index, name, teamObject) => {
//updates checked team state
//prevents all teams being unselected
if(name === this.state.checkedTeams[0]) {
this.setState({ checkMessage: `Don't you want something to look at?` })
} else {
if(!this.state.checkedTeams.includes(name)){
this.state.checkedTeams[this.state.checkedTeams.length] = name
this.setState({ checkedTeams: [...this.state.checkedTeams] })
//sets team object with new team object
this.state.teamObject[this.state.teamObject.length] = teamObject
this.setState({ teamObject: this.state.teamObject })
} else {
newChecked = this.state.checkedTeams.filter(v => { return v !== name})
this.setState({ checkedTeams: newChecked })
//removes team object and sets new state
newObjectChecked = this.state.teamObject.filter(v => { return v.team_name !== teamObject.team_name})
this.setState({ teamObject: newObjectChecked })
}
//updates checkbox for specific space
this.state.checked[index] = !this.state.checked[index]
this.setState({ checked: this.state.checked })
}
}
changeTeamSelect = (index) => {
this.state.accordionStatus[index] = !this.state.accordionStatus[index]
this.setState({ accordionStatus: this.state.accordionStatus})
}
render(){
return(
<View>
<View>
<Text
style={{
fontFamily: 'Helvetica',
fontSize: 13,
paddingLeft: 5,
paddingBottom: 5
}}
onPress={()=> this.changeTeamSelect(0)}
>
NFL TEAM SELECT
</Text>
</View>
{
this.state.accordionStatus[0] === false ? null :
<View
style={{
flexDirection: 'row',
paddingLeft: 10,
flexWrap: 'wrap'
}}
>
{
this.props.team.map(
(v, i) => {
if(v.league.acronym === 'NFL'){
return(
<Check
key={i}
checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false*/ }
index={i}
teamObject={v}
value={v.team_name}
changeCheck={this.changeCheck}
/>
)
}
}
)
}
</View>
}
<View>
<Text
style={{
fontFamily: 'Helvetica',
fontSize: 13,
paddingLeft: 5,
paddingBottom: 5
}}
onPress={()=> this.changeTeamSelect(1)}
>
NBA TEAM SELECT
</Text>
</View>
{
this.state.accordionStatus[1] === false ? null :
<View
style={{
flexDirection: 'row',
paddingLeft: 10,
flexWrap: 'wrap'
}}
>
{
this.props.team.map(
(v, i) => {
if(v.league.acronym === 'NBA'){
return(
<Check
key={i}
checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false*/ }
index={i}
teamObject={v}
value={v.team_name}
changeCheck={this.changeCheck}
/>
)
}
}
)
}
</View>
}
<View>
<Text
style={{
fontFamily: 'Helvetica',
fontSize: 13,
paddingLeft: 5,
paddingBottom: 5
}}
onPress={()=> this.changeTeamSelect(2)}
>
MLB TEAM SELECT
</Text>
</View>
{
this.state.accordionStatus[2] === false ? null :
<View
style={{
flexDirection: 'row',
paddingLeft: 10,
flexWrap: 'wrap'
}}
>
{
this.props.team.map(
(v, i) => {
if(v.league.acronym === 'MLB'){
return(
<Check
key={i}
checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false */}
index={i}
teamObject={v}
value={v.team_name}
changeCheck={this.changeCheck}
/>
)
}
}
)
}
</View>
}
</View>
)
}
}
function mapStateToProps(state) {
return {
league: state.league.league,
team: state.team.team,
checkedLeagues: state.league.checkedLeagues,
checkedTeams: state.league.checkedTeams,
queryTeams: state.league.queryTeams
}
}
export default connect(mapStateToProps, { loadCards, changeLeagues })(TeamSelect)
Something to note, I use redux to update the state, place it into a store, and then use it when the component is mounts again. What is interesting is that this.state.checkedLeagues preserves state as it should in the first component, however, this.state.checkedTeams does not preserve it's state in the second component. Any ideas why?
EDIT:
This is my LeagueReducer:
let defaultState = {
league: null,
checkedLeagues: null,
checkedTeams: null,
queryTeams: null,
teamObject: null
}
export function LeagueReducer(state = defaultState, action){
if(action.type === "CHANGE_LEAGUES") {
return {
...state,
league: action.league,
checkedLeagues: action.checkedLeagues,
checkedTeams: action.checkedTeams,
queryTeams: action.queryTeams,
teamObject: action.teamObject
}
} else {
return state
}
}

Looks like it's possible you're not updating the redux store correctly. Remember do not use array functions that mutate the array like push. You need to use functions like concat that return a new array.

Related

How to make reusable component in react-native and call them inside other component?

I have a modal component that I want to reuse in future component.
For this reason I want to have it in its own file.
I don't manage to call the component inside the other properly though.
Here is my last attempt of it.
The Modal component code:
export const FlyingDescription = (cityDescription) => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<Modal
animation="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => setModalVisible(!modalVisible)}
>
<View style={styleBoxParent}>
<View style={styleBoxChildren}>
<LinearGradient
style={styleLinearGradient}
colors={['#136a8a', '#267871']}
start={[0, 0.65]}
>
<Text style={styleText}>{cityDescription}</Text>
<Pressable
onPress={() => setModalVisible(!modalVisible)}
>
<Text style={styleText}>Close</Text>
</Pressable>
</LinearGradient>
</View>
</View>
</Modal>
</View>
);
};
The component where I want to call the Modal component:
import FlyingDescription from './FlyingDescription.js';
var utils = require('./utils');
export default class SearchScreen extends React.Component {
constructor(props) {
super(props);
this.navigation = props.navigation;
this.state = {
searchInput: '',
item : {},
renderSearch: false,
renderFlyingDescription: false,
};
this.errorMessage = 'Search for cities...';
}
resetState = () => {
this.setState({
item: {},
renderable: false,
}); }
setSearchInput = (value) => {
this.setState({
searchInput: value
});
}
searchCity = () => {
this.resetState();
utils.fetchWeather(this.state.searchInput).then(response => {
if (response.cod == 200) {
console.log(response);
this.setItemState(
{
name: response.name,
temp: Math.ceil(response.main.temp),
type: response.weather[0].main,
desc: 'Humidity: ' + response.main.humidity + '% - ' + response.weather[0].main
}
);
this.setRenderSearch();
}
});
}
setItemState = (newItem) => {
this.setState(
{
item: newItem,
}
);
}
setRenderSearch = () => {
this.setState(
{
renderSearch: true,
}
);
}
render = () => {
return(
<View style={utils.style.container}>
<StatusBar barStyle="light-content" />
<Text style={utils.style.titleContainer}>☀️ CityWeather</Text>
<View style={{alignItems: 'center', width:'90%'}}>
<Text>Search for a city</Text>
<TextInput
onChangeText={(value) => this.setSearchInput(value)}
value={this.searchInput}
style={{ width: '80%', padding: 15, margin: 5, backgroundColor: 'black', color: 'white' }}
/>
<TouchableHighlight
style={{backgroundColor: 'grey', padding: 20, borderRadius: 8}}
onPress={this.searchCity}
>
<Text style={{fontSize: 14, color:'white'}}>Search</Text>
</TouchableHighlight>
</View>
{ this.state.renderSearch ? (
<TouchableHighlight
underlayColor="white"
onPress={ () => this.setState({renderFlyingDescription: true})}
>
<LinearGradient
colors={['rgba(0,0,0,0.05)', 'rgba(0,0,0,0)']}
start={[0, 0.5]}
>
<View style={utils.style.row}>
<Text style={[utils.getTempRange(this.state.item.temp), utils.style.temp]}>
{utils.getEmoji(this.state.item.type)} {this.state.item.temp} °C
</Text>
<Text style={utils.style.cityName}>{this.state.item.name}</Text>
</View>
</LinearGradient>
</TouchableHighlight>
) : (
// WHERE I WANT TO RENDER MY MODAL COMPONENT
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center', fontSize: 32}}>
<Text>{this.errorMessage}</Text>
</View>
)
}
{
renderFlyingDescription(this.state.renderFlyingDescription, this.state.item.desc)
}
</View>
);
}
}
export function renderFlyingDescription(isInterpretable, cityDescription) {
if(isInterpretable) {
return <FlyingDescription cityDescription={cityDescription} />
}
}

how do i get and show the total sum objects that arrive from my JSON in a footer at the bottom of the screen?

At my example, the function “getData” loading my data, but after the loading, I try to print and show the total sum of the objects that came from JSON in a footer at the bottom of the screen.
and I don't really know how to do it.
I don't understand how to solve this issue coz I have tried many ways.
This is my example:
export default class MainScreen extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
}
getData = () => {
this.setState({ isLoading: true })
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
console.log(res.data);
});
}
componentDidMount() {
this.props.navigation.setParams({getData: this.getData}); //Here I set the function to parameter
this.getData()
}
renderItem(item) {
const { title, artist} = item.item;
return (
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Settings")}
>
<Card
containerStyle={{
borderColor: "black",
padding: 20,
height: 100,
backgroundColor: "#e6e6ff",
borderBottomEndRadius: 10,
borderTopRightRadius: 10,
borderBottomStartRadius: 10,
}}
>
<View
style={{
paddingVertical: 15,
paddingHorizontal: 10,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
}}
>
<Icon name="chevron-right" size={30} color={"grey"} justifyContent={"space-between"} />
<Text style={styles.name}>
{title+ " " + artist}
</Text>
{/* <Text style={styles.vertical} numberOfLines={2}></Text> */}
</View>
</Card>
</TouchableOpacity>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 230 }}>
<Text
style={{ alignSelf: "center", fontWeight: "bold", fontSize: 20 }}
>
loading data...
</Text>
<ActivityIndicator size={'large'} color={'#08cbfc'} />
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
/>
</View>
);
}
}
/////////////////////////////////////////////////////////
MainScreen.navigationOptions = navData => {
return {
headerTitle: 'melon',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title=**"sync button"**
iconName={Platform.OS === "android" ? "md-sync" : "ios-sync"}
onPress={() => {
navData.navigation.navigate("getData");
}}
/>
</HeaderButtons>
)
};
};
If type of data is array you can get total number of elements by this.state.data.length
If type of data is object you can get total number of elements by Object.keys(data).length

Passing data to custom picker

Currently I'm developing an app with a picker on it and I'm using picker component from react native but it doesn't work perfectly on iOS device so I found a custom picker using picker and modal it renders a modal on iOS only.
Here is the code
class PickerWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
type_absen: '',
modal: false,
}
}
render() {
let picker;
let iosPickerModal = (
<Modal isVisible={this.state.modal} hideModalContentWhileAnimating={true} backdropColor={color.white} backdropOpacity={0.9} animationIn="zoomInDown" animationOut="zoomOutUp" animationInTiming={200} animationOutTiming={200} onBackButtonPress={() => this.setState({ modal: false })} onBackdropPress={() => this.setState({ modal: false })} >
<View style={{ backgroundColor: color.white, width: 0.9 * windowWidth(), height: 0.3 * windowHeight(), justifyContent: 'center' }}>
<Picker
selectedValue={this.state.type_absen}
onValueChange={(itemValue, itemIndex) => {
this.setState({ type_absen: itemValue });
this.setState({ modal: false });
setTimeout(() => this.props.onSelect(itemValue), 1200);
}}
>
{this.props.items.map((item, key) => <Picker.Item label={item} value={item} key={key} />)}
</Picker>
</View>
</Modal>);
if (Platform.OS === 'ios')
return (
<View style={this.props.style}>
{iosPickerModal}
<TouchableOpacity onPress={() => this.setState({ modal: true })}>
<View style={{ flexDirection: 'row', height: this.props.height ? this.props.height : normalize(40), width: this.props.width ? this.props.width : 0.68 * windowWidth(), borderWidth: 1, borderColor: color.blue, alignItems: 'center', borderRadius: 5 }}>
<Text style={{ fontSize: fontSize.regular, marginRight: 30 }}> {this.state.type_absen}</Text>
<IconWrapper name='md-arrow-dropdown' type='ionicon' color={color.light_grey} size={20} onPress={() => this.setState({ modal: true })} style={{ position: 'absolute', right: 10 }} />
</View>
</TouchableOpacity>
</View >);
else
return (
<View style={this.props.style} >
<Picker
selectedValue={this.state.type_absen}
style={{ height: this.props.height ? this.props.height : normalize(20), width: this.props.width ? this.props.width : normalize(150) }}
onValueChange={(itemValue, itemIndex) => {
this.setState({ type_absen: itemValue });
this.props.onSelect(itemValue);
}}
>
{this.props.items.map((item, key) => <Picker.Item label={item} value={item} key={key} />)}
</Picker>
</View>);
}
}
PickerWrapper.propTypes = {
onSelect: PropTypes.func.isRequired
}
export default PickerWrapper;
I successfully load the data from api, but I still confused on how to get the value from it, and here is my old code using picker component
<Picker
selectedValue={this.state.type_absen}
style={{backgroundColor:'white'}}
onValueChange={(val) => this.setState({ type_absen: val })}>
{
this.props.schedules ? this.props.schedules.map((item, key) => {
return <Picker.Item value={item.id} label {item.description} key={item.id} />})
:
[]
}
</Picker>
and this is my new code using the PickerWrapper
export const mapStateToProps = state => ({
token: state.authReducer.token,
message: state.authReducer.message,
schedules: state.authReducer.schedules
});
export const mapDispatchToProps = (dispatch) => ({
actionsAuth: bindActionCreators(authAction, dispatch)
});
class Change extends Component {
constructor(){
super();
this.state={
type_absen: [],
}
}
onPickerValueChange=(value, index)=>{
this.setState({type_absen: value},
() => {
Alert.alert("type_absen", this.state.type_absen);
}
);
}
render() {
return (
<View style={styles.container}>
<View style={styles.container}>
<View style={styles.innerContainer}>
<PickerWrapper items={this.props.schedules.map((item) => item.description )} onSelect={this.onPickerValueChange} />
</View>
</View>
</View>
);
}
}
}
what I'm trying to do is get the item.id. How do I do that in my PickerWrapper component?
In the class component change the picker wrapper like this
export const mapStateToProps = state => ({
token: state.authReducer.token,
message: state.authReducer.message,
schedules: state.authReducer.schedules
});
export const mapDispatchToProps = (dispatch) => ({
actionsAuth: bindActionCreators(authAction, dispatch)
});
class Change extends Component {
constructor(){
super();
this.state={
type_absen: [],
}
}
onPickerValueChange=(value, index)=>{
this.setState({type_absen: value},
() => {
Alert.alert("type_absen", this.state.type_absen);
}
);
}
render() {
return (
<View style={styles.container}>
<View style={styles.container}>
<View style={styles.innerContainer}>
<PickerWrapper items={this.props.schedules} onSelect={this.onPickerValueChange.bind(this)} />
</View>
</View>
</View>
);
}
}
and then in your PickerWrapper component change it to be like this
class PickerWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
type_absen: '',
modal: false,
}
}
render() {
let picker;
let iosPickerModal = (
<Modal isVisible={this.state.modal} hideModalContentWhileAnimating={true} backdropColor={color.white} backdropOpacity={0.9} animationIn="zoomInDown" animationOut="zoomOutUp" animationInTiming={200} animationOutTiming={200} onBackButtonPress={() => this.setState({ modal: false })} onBackdropPress={() => this.setState({ modal: false })} >
<View style={{ backgroundColor: color.white, width: 0.9 * windowWidth(), height: 0.3 * windowHeight(), justifyContent: 'center' }}>
<Picker
selectedValue={this.state.type_absen}
onValueChange={(itemValue, itemIndex) => {
this.setState({ type_absen: itemValue });
this.setState({ modal: false });
setTimeout(() => this.props.onSelect(itemValue), 1200);
}}
>
{this.props.items.map((item, key) => <Picker.Item label={item.description} value={item.id} key={key} />)}
</Picker>
</View>
</Modal>);
if (Platform.OS === 'ios')
return (
<View style={this.props.style}>
{iosPickerModal}
<TouchableOpacity onPress={() => this.setState({ modal: true })}>
<View style={{ flexDirection: 'row', height: this.props.height ? this.props.height : normalize(40), width: this.props.width ? this.props.width : 0.68 * windowWidth(), borderWidth: 1, borderColor: color.blue, alignItems: 'center', borderRadius: 5 }}>
<Text style={{ fontSize: fontSize.regular, marginRight: 30 }}> {this.state.type_absen}</Text>
<IconWrapper name='md-arrow-dropdown' type='ionicon' color={color.light_grey} size={20} onPress={() => this.setState({ modal: true })} style={{ position: 'absolute', right: 10 }} />
</View>
</TouchableOpacity>
</View >);
else
return (
<View style={this.props.style} >
<Picker
selectedValue={this.state.type_absen}
style={{ height: this.props.height ? this.props.height : normalize(20), width: this.props.width ? this.props.width : normalize(150) }}
onValueChange={(itemValue, itemIndex) => {
this.setState({ type_absen: itemValue });
this.props.onSelect(itemValue, index);
}}
>
{this.props.items.map((item, key) => <Picker.Item label={item.description} value={item.id} key={key} />)}
</Picker>
</View>);
}
}
PickerWrapper.propTypes = {
onSelect: PropTypes.func.isRequired
}
export default PickerWrapper;

How can I switch to the second input when first will be done in React Native

I am creating a Taxi Application just like Uber where user enters two locations in given inputs (Pickup and Dropoff), I done with the PickUp when User enters a location it shows the googleautocomplete listview for location and can select the pickup location, but I am stuch with the Dropoff when I write something in the second input it changes the first too or when I click the clear icon it clears text from both inputs. So what do I have to do to solve this problem kindly help please Thanks.
AutoCompeleteInputs.js
import React from 'react';
import { TextInput, View, StyleSheet, Animated, TouchableOpacity } from "react-native";
import AutoCompleteListView from "./AutoCompleteListView";
import Events from "react-native-simple-events";
import debounce from '../utils/debounce'
import fetch from 'react-native-cancelable-fetch';
import MaterialIcons from "react-native-vector-icons/MaterialIcons";
const AUTOCOMPLETE_URL = "https://maps.googleapis.com/maps/api/place/autocomplete/json";
const REVRSE_GEO_CODE_URL = "https://maps.googleapis.com/maps/api/geocode/json";
export default class AutoCompleteInput extends React.Component {
static defaultProps = {
language: 'en'
};
constructor(props) {
super(props);
}
componentWillUnmount() {
this._abortRequest();
}
state = {
predictions: [],
loading: false,
inFocus: false,
};
_abortRequest = () => {
fetch.abort(this);
};
fetchAddressForLocation = (location) => {
this.setState({ loading: true, predictions: [] });
let { latitude, longitude } = location;
fetch(`${REVRSE_GEO_CODE_URL}?key=${API_KEY}&latlng=${latitude},${longitude}`, null, this)
.then(res => res.json())
.then(data => {
this.setState({ loading: false });
let { results } = data;
if (results.length > 0) {
let { formatted_address } = results[0];
this.setState({ text: formatted_address });
}
});
}
_request = (text) => {
this._abortRequest();
if (text.length >= 3) {
fetch(`${AUTOCOMPLETE_URL}?input=${encodeURIComponent(text)}&key=${API_KEY}&language=${this.props.language}`, null, this)
.then(res => res.json())
.then(data => {
let { predictions } = data;
this.setState({ predictions });
});
} else {
this.setState({ predictions: [] });
}
}
_onChangeText = (text) => {
this._request(text);
this.setState({ text });
}
_onFocus = () => {
this._abortRequest();
this.setState({ loading: false, inFocus: true });
Events.trigger('InputFocus');
}
_onBlur = () => {
this.setState({ inFocus: false });
Events.trigger('InputBlur');
}
blur = () => {
this._input.blur();
}
_onPressClear = () => {
this.setState({ text: '', predictions: [] });
}
_getClearButton = () => {
return this.state.inFocus ?
(<TouchableOpacity style={styles.btn} onPress={this._onPressClear}>
<MaterialIcons name={'clear'} size={20} />
</TouchableOpacity>) : null;
}
getAddress = () => {
return this.state.loading ? '' : this.state.text;
}
render() {
return (
<Animated.View style={this.props.style}>
<View style={{ flexDirection: 'column' }}>
<View
style={styles.textInputPickupContainer}
elevation={5}>
<TextInput
ref={input => this._input = input}
value={this.state.loading ? 'Loading...' : this.state.text}
style={styles.textInput}
underlineColorAndroid={'transparent'}
placeholder={'Pickup'}
onFocus={this._onFocus}
onBlur={this._onBlur}
onChangeText={this._onChangeText}
outlineProvider='bounds'
autoCorrect={false}
spellCheck={false} />
{this._getClearButton()}
</View>
<View
style={styles.textInputDropoffContainer}
elevation={5}>
<TextInput
ref={input => this._input = input}
value={this.state.loading ? 'Loading...' : this.state.dropOff}
style={styles.textInput}
underlineColorAndroid={'transparent'}
placeholder={'Dropoff'}
onFocus={this._onFocus}
onBlur={this._onBlur}
onChangeText={(text) => this.setState({dropOff: text})}
outlineProvider='bounds'
autoCorrect={false}
spellCheck={false} />
{this._getClearButton()}
</View>
</View>
<View style={styles.listViewContainer}>
<AutoCompleteListView
predictions={this.state.predictions} />
</View>
</Animated.View>
);
}
}
const styles = StyleSheet.create({
textInputPickupContainer: {
flexDirection: 'row',
height: 40,
zIndex: 10,
paddingLeft: 10,
borderRadius: 5,
backgroundColor: 'white',
shadowOffset: {
width: 0,
height: 2
},
shadowRadius: 2,
alignItems: 'center'
},
textInputDropoffContainer: {
flexDirection: 'row',
height: 40,
zIndex: 10,
paddingLeft: 10,
marginTop: 10,
borderRadius: 5,
backgroundColor: 'white',
shadowOffset: {
width: 0,
height: 2
},
shadowRadius: 2,
alignItems: 'center'
},
textInput: {
flex: 1,
fontSize: 17,
color: '#404752'
},
btn: {
width: 30,
height: 30,
padding: 5,
justifyContent: 'center',
alignItems: 'center'
},
listViewContainer: {
paddingLeft: 3,
paddingRight: 3,
paddingBottom: 3
},
});
SearchRoute.js(Main)
return (
<View style={styles.container}>
<MapView
ref={(mapView) => this._map = mapView}
style={styles.mapView}
region={this.state.region}
showsMyLocationButton={true}
showsUserLocation={false}
onPress={({ nativeEvent }) => this._setRegion(nativeEvent.coordinate)}
onRegionChange={this._onMapRegionChange}
onRegionChangeComplete={this._onMapRegionChangeComplete}
/>
<Entypo name={'location-pin'} size={30}
color={this.props.markerColor}
style={{ backgroundColor: 'transparent' }} />
<View style={styles.fullWidthContainer}>
<AutoCompleteInput
ref={input => this._input = input}
apiKey={API_KEY}
style={[styles.input, { transform: [{ scale: inputScale }] }]}
debounceDuration={this.props.debounceDuration}
/>
</View>
The error is that you are assigning the same value to both TextInputs, so if you change one, the other TextInput will change too to the same value.
On your AutoCompeleteInputs.js change dropOff TextInput's value to
<TextInput
...
value={this.state.loading ? 'Loading...' : this.state.dropOff}
...
/>
So when you change dropOff value, the pickUp point will be the same you entered before, and if you clear one the other will not change.
Also change dropOff onChangeText={this._onChangeText} to onChangeText={(text) => this.setState({dropOff: text}) to ensure that you are storing the correct value.

React native how clear ram when component unmount?

How delete cache(images, item, component), from ram when component unmount?
Now, when a new View is opened, the RAM is not cleared.
After I move on to another activity memory is not cleared and modern is overflowing.
Every time a new component is opened, even if it was previously opened, the amount of memory used increases.
Sorry for my bad english.
export default class Articles extends PureComponent {
constructor(props, context) {
super(props, context)
this.state = {
renderPlaceholderOnly: true,
unMountStatus: true,
}
}
componentWillMount() {
let { params } = this.props.navigation.state
this.props.fetchData(params.id)
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.setState({renderPlaceholderOnly: false})
})
}
componentWillUnMount() {
this.setState({
unMountStatus: false
})
this.props.dataArticles.data = []
this.props.unFetchData()
console.log(this.props)
this.props = []
console.log(this.props)
}
_renderPlaceholderView() {
return (
<View>
<Spinner color={'#575757'} visible={true} textContent={"Loading..."} textStyle={{color: '#575757'}} />
</View>
)
}
_addUrlToCache(url) {
ImageResizer.createResizedImage(url, 375, 175, 'JPEG', 75, 0)
.then((resizedImageUri) => {
cache.put('lalka2', resizedImageUri)
}).catch((err) => {
console.log(err)
})
return cache.get("lalka2")
}
render() {
const { navigate } = this.props.navigation
console.log(this._addUrlToCache("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoiqLLZMXTvg385j12vAs_P9PN3Cv9t3udbBwGnBYwFjC1dPuD"))
if (this.state.renderPlaceholderOnly) {
return this._renderPlaceholderView()
}
return (
<View style={styles.container}>
<Header menuOpen={this.openControlPanel} title={'Articles'} navigate={this.props.navigation}/>
<Spinner color={'#575757'} visible={this.props.dataArticles.isFetching} textContent={"Loading..."} textStyle={{color: '#575757'}} />
{ this.state.unMountStatus ? <ScrollView>
{
this.props.dataArticles.data.length > 0 ? this.props.dataArticles.data.map((item, index) => {
return (
<Card style={{ flex: 0 }} key={index}>
<CardItem style={{backgroundColor: 'white', borderColor: '#841010', borderBottomWidth: 1}}>
<Left>
<Body>
<Text style={{fontFamily: 'Roboto', color: "#841010"}}>{item.title}</Text>
<Text note style={{fontFamily: 'Roboto', color: "#6B0D0D"}}>{item.publishedAt}</Text>
</Body>
</Left>
</CardItem>
<CardItem>
<Body>
<Text style={{fontFamily: 'Roboto'}}>
{item.description}
</Text>
<Button transparent textStyle={{color: '#87838B', fontSize: 28}} onPress={() => navigate('WebView', { authorArticle: 'Article', url: item.url })}>
<Icon style={{color: "#841010"}} name="link" />
<Text style={{ color: "#841010", fontFamily: 'Roboto'}}>Read More</Text>
</Button>
</Body>
</CardItem>
</Card>
)
}) : <View></View>
}
</ScrollView> : null
}
</View>
);
}
}

Categories