How to setState in different component React native? - javascript

My data from the api is loaded in a component and returns a view containing the values, which does show in the other component. But I want an activity indicator on that page to show until the data is completely loaded.
I've followed some tutorials about setState with parent-child, child-parent, sibling-sibling and parentless relations. But none seem to work the way I want it.
This is the screen that shows first. It starts with the 'refreshing' view, which will show an activityindicator until the state.refreshing is set to false.
export default class AgendaScreen extends React.Component {
static navigationOptions = {
title: "Agenda"
};
constructor(props) {
super(props);
this.state={
refreshing: true
}
}
render() {
if (this.state.refreshing){
return(
//loading view while data is loading
<ImageBackground source={ScreenBackground} style={styles.container}>
<View style={{flex:1, paddingTop:20}}>
<ActivityIndicator />
</View>
</ImageBackground>
)
}
return(
<ImageBackground source={ScreenBackground} style={styles.container}>
<ScrollView>
<ImageBackground style={[styles.header,{justifyContent:'flex-end'}]} source = {HeaderImage}>
<Text style={{color:'white', fontSize:12, alignSelf:'center', backgroundColor:'transparent', marginBottom:2}}>
Complete summary
</Text>
</ImageBackground>
<Text style={styles.text}>Agenda</Text>
<Dates />
</ScrollView>
</ImageBackground>
);
}
}
This is the dates component, which gives me the view that I call with in the previous code block.
export default class Dates extends React.Component {
constructor(props) {
super(props);
this.state = {
data:[],
fill:[],
refreshing:true,
dates:[],
list:[]
}
}
componentDidMount() {
this.getData();
}
getData() {
fetch("API")
.then((result)=>result.json())
.then((res=>{
this.setState({
data:res,
refreshing:false
});
this.setState({
fill:this.state.data[0]
});
this.getDates();
this.loop();
}))
.catch(error =>{
console.error(error);
});
};
onRefresh() {
//Clear old data
this.setState({
data:[]
});
//Function to call api for latest data
this.getData();
};
getDates() {
var str = t(this.state.test, 'content.rendered').safeString
var arr = str.split(',');
var dates = [];
arr.forEach(function(e) {
dates.push(e.match(/;(\d{0,2}.[a-zA-Z]+)/g)[0].replace(';',''));
});
this.setState({
dates: dates
})
};
tempList=[];
loop(){
for (x=0;x<this.state.data.length;x++)
{
var fill=this.state.data[x]
this.tempList.push(
<View style={{flex:1}}>
<FlatList
data={[fill]}
renderItem={({item})=>
<View>
<Text style={styles.text}>
{t(item, 'title.rendered').safeObject}
</Text>
</View>
}
refreshControl={
<RefreshControl
//refresh control used for pull to refresh
refreshing={this.state.refreshing}
onRefresh={this.onRefresh.bind(this)}
/>
}
keyExtractor={(item, index) => index.toString()}
/></View>
)
}
this.setState({
list:this.tempList
})
}
render() {
return(
<View style={{flex:1, borderWidth:10}}><Text></Text>{this.state.list}
</View>
);
}
}
What I need is when Dates succesfully loaded his data from the api and returns the view, that the AgendaScreen state.refreshing will be stated to false.

Add below to your AgendaScreen Component
this.refresHandler = (e) =>{
this.setState({
refreshing:e
})
}
Add below props inside <Dates />
<Dates refresHandler={this.refresHandler}/>
change below code in Dates Component
getData() {
fetch("API")
.then((result)=>result.json())
.then((res=>{
this.setState({
data:res,
refreshing:false
});
this.setState({
fill:this.state.data[0]
});
this.getDates();
this.loop();
}))
.then(() =>{
this.props.refresHandler(this.state.refreshing)
})
.catch(error =>{
console.error(error);
});
}

Related

How can I pass a selected object from an array (firestore) to another class in react native?

I have a question about passing specific Objects from an array to another class in react native. If I press the button, all objects go to another class instead of the one I need, but I want the one which I pressed. Do I have to create a function for the selected object/ key or is it enough if I change something in the onPress={} method?
I need to change something here -> TouchableOpacity onPress={()=>this.props.navigation.navigate('detail', item,{})}> Item must be the document (firestore) with all the information I have, but how can I pass the object from the array only?
Here are also some pictures for a better understanding, thank you in advance
export default class foods extends Component {
constructor(props) {
super(props);
this.state = {
posts:[],
}
}
componentDidMount() {
StatusBar.setHidden(true)
this.subscriber = database.collection('users').onSnapshot(docs => {
let posts = []
docs.forEach(document => {
posts.push({
id: document.id,
...document.data(),
})
})
this.setState({posts})
console.log(posts)
})
}
render() {
return (
<ScrollView>
<View style={styles.container}>
{
this.state.posts.map((item) => {
return (
<View >
{
Object.keys(item.post).map((key) => {
return (
<View style={styles.card}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('detail', item, {})}>
<Text>{item.firstName} {item.lastName}</Text>
<Image style={styles.cardImage} source={{ uri: item.post[key].image }} />
<Text>{item.post[key].essenname}</Text>
</TouchableOpacity>
</View>
)
})
}
</View>
)
})
}
</View>
</ScrollView>
);
}
}
export default class detail extends Component {
constructor(props) {
super(props);
this.state = {
post: [this.props.route.params]
}
};
componentDidMount() {
StatusBar.setHidden(true)
console.log('Array : ', this.state.post)
}
render() {
return (
<View style={styles.container}>
<ScrollView>
{this.state.post.map((item) => {
return (
Object.keys(item.post).map((key) => {
return (
<View style={styles.card}>
<Image style={styles.cardImage} source={{ uri: item.post[key].image }} />
<Text>{item.post[key].essenname}</Text>
</View>
)
})
)
})}
</ScrollView>
</View>
);
}
}
I want to pass either Post[0] or Post[1] but not both:
![](https://i.stack.imgur.com/3recX.png)
This is my output, which is the same output after navigating the item to the detail screen:
![](https://i.stack.imgur.com/WMqrd.png)
Detail screen on the right:
![](https://i.stack.imgur.com/gIX0V.png)
The document with the array 'post':
![](https://i.stack.imgur.com/dO1uQ.png)
There is no need to use Object.keys to loop trought your posts, just use item.post.
In your navigation params, just use a spred operator for the root key and pass the post selected: this.props.navigation.navigate('detail', {posts: {...this.state.posts, post: [p]}}).
In your detail component state your are missing to access the params, it should be:
this.state={
post:[this.props.route.params.posts]
}
and replace Object.keys with item.post

Can we use this.props.map as well as this.props.navigation in single class to navigate to another screen

I have used this.props.maps as well as this.props.navigation which is showing an error:
this.props.navigation.navigate is undefined object
Trying to navigate to another page by rendering the firebase database but getting error but the same code i tried by simple creating a view and navigating to another page then it is working
export default class ItemComponent extends Component {
constructor(props) {
super(props);
// need to bind `this` to access props in handler
this._onEditLibrary = this._onEditLibrary.bind(this);
}
static propTypes = {
items: PropTypes.array.isRequired
};
_onEditLibrary=()=> {
this.props.navigation.navigate('EditLibrary');
};
render() {
return (
<View style={styles.itemsList}>
<TouchableOpacity onPress={this._onEditLibrary}>
{this.props.items.map((item, index) => {
return (
<View key={index}>
<ImageBackground source={item.Image} style={ { height:150, width:150}}>
<Text style={styles.itemtext}>{item.Name}</Text>
</ImageBackground>
</View>
)
})
}
</TouchableOpacity>
</View>
);
}
}
Need to navigate to another page
Try this out
export default class ItemComponent extends Component {
constructor(props) {
super(props);
// need to bind `this` to access props in handler
this._onEditLibrary = this._onEditLibrary.bind(this);
}
static propTypes = {
items: PropTypes.array.isRequired
};
_onEditLibrary=()=> {
this.props.navigation.navigate('EditLibrary');
};
render() {
return (
<View style={styles.itemsList}>
{this.props.items.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={this._onEditLibrary}>
<ImageBackground source={item.Image} style={ { height:150, width:150}}>
<Text style={styles.itemtext}>{item.Name}</Text>
</ImageBackground>
</TouchableOpacity>
)
})
}
</View>
);
}
}

How to call a child method from the parent in React Native?

When a click event is fired within my parent component I need to call the method closeMenu() from the SearchBar child component. I have tried a couple of different ways to do that but none of them are working. Does anyone know how to do this?
class Products extends Component {
constructor(props) {
super(props);
this.state = { closeMenu: false};
this.hideSearchBar = this.hideSearchBar.bind(this);
}
hideSearchBar(e) {
console.log('e: ', React.Children)
this.setState({closeMenu: true});
this.refs.SearchBar.closeMenu();
this.setState({closeMenu: false});
}
componentWillMount() {
this.props.dispatch(getProductList());
}
render() {
const {isLoading, products} = this.props.products;
if (isLoading) {
return <Loader isVisible={true}/>;
}
return (
<TouchableWithoutFeedback onPress={(e) => this.hideSearchBar(e)} style={{zIndex: 0}}>
<View style={styles.wrapper}>
<Header/>
<View style={styles.bodyWrapper}>
<ScrollView style={styles.scrollView}>
<ProductsContainer data={{productsList: { results: products }}}/>
</ScrollView>
<SearchBar ref="SearchBar" style={styles.searchBar} />
</View>
<Footer/>
</View>
</TouchableWithoutFeedback>
);
}
}
I also tried calling closeMenu() without refs:
hideSearchBar(e) {
this.setState({closeMenu: true});
this.SearchBar.closeMenu();
}
Here is the SearchBar component:
class SearchBar extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.suggestions = [];
}
componentWillUpdate(nextProps, nextState) {
console.log("COMPONENT WILL UPDATE");
console.log(nextProps);
console.log(nextState);
}
suggestionClick = (value) => {
}
getSuggestionText = (suggestion) => {
}
onChangeText = (value) => {
this.selectedSuggestion = false
this.props.dispatch(handleSearchItemText(value));
console.log(this.props.products.searchResults);
}
onFocus() {
const {height} = Dimensions.get('window');
this.setState({
contentOffset: {
x: 0,
y: height * 1 / 3
}
});
}
onBlur() {
this.setState({
contentOffset: {x: 0, y: 0}
});
}
closeMenu = () => {
this.props.products.searchResults = {};
}
componentWillReceiveProps() {
if (!this.props.closeMenu) {
this.props.closeMenu = false;
}
}
renderSearches = () => {
this.suggestions = this.props.products.searchResults;
const suggestionTexts = Object.keys(this.props.products.searchResults || {})
console.log(suggestionTexts);
if (!suggestionTexts.length) {
return null
}
// for android absolute element: https://github.com/facebook/react-native/issues/16951
// https://gist.github.com/tioback/6af21db0685cd3b1de28b84981f31cca#file-input-with-suggestions-L54
return (
<View
ref="suggestionsWrapper"
style={autoStyles.suggestionsWrapper}
>
{
this.suggestions.map((text, index) => (
<TouchableHighlight
key={index}
suggestionText={text}
activeOpacity={0.6}
style={autoStyles.suggestion}
onPress={this.suggestionClick(this.suggestions[text])}
underlayColor='white'
>
<Text style={autoStyles.suggestionText}>
{text}
</Text>
</TouchableHighlight>
))
}
</View>
)
}
render() {
const myIcon = (<Icon name="search" size={30} style={styles.searchIcon}/>);
const slidersIcon = (<Icon name="sliders" size={30} style={styles.slidersIcon}/>);
return (
<TouchableWithoutFeedback style={{zIndex: 0}}>
<View style={[styles.searchBar, this.props.style]}>
<View style={styles.searchContainer}>
<View>
{slidersIcon}
</View>
<View style={styles.search}>
<View style={styles.searchSection}>
{myIcon}
<TextInput
style={styles.input}
placeholder="Search"
placeholderTextColor="rgba(0,0,0,0.7)"
onChangeText={(searchString) => {
this.setState({searchString})
}}
underlineColorAndroid="transparent"
editable={true}
autoCorrect={false}
autoFocus={false}
autoCaptialize={'none'}
autoCorrect={false}
onChangeText={this.onChangeText}
enablesReturnKeyAutomatically={true}
onFocus={() => this.onFocus()}
onBlur={() => this.onBlur()}
/>
</View>
</View>
</View>
{this.renderSearches()}
</View>
</TouchableWithoutFeedback>
);
}
}
There are some issues which you should avoid:
Never mutate props: this.props.something = {} is an anti-pattern. Think about props as data that your component does not own and which are not mutable. If they change then only because the parent passed new props.
Also you have multiple handlers in your SeachBar that are not bound to this but use this. It will not work. Use arrow functions if you want to use this or bind them in the constructor.
You should overthink the architecture of your app. Maybe it is a good idea to split the search bar and the result list into two separate components. When the user types something to search for update your redux store and display the results in a separate component that you only render if there are search results.
I'm affraid it would exceed the length of a stackoverflow answer to solve all these issues. Maybe you should go back to the basics first and do the really good redux tutorial.

How to pass props from FlatList item to Modal?

I have implemented a View component containing a FlatList, which renders TouchableHighlights. Also I have implemented a Modal component, which I'd like to import at various places including the component that renders the FlatList.
I have already managed to open the modal from outside (via handing over a prop for visibility, accessing it via nextProps and setting modals state value "modalVisible" to this) and closing it from inside (simply via changing it's state value "modalVisible").
BUT: I also want to pass data to the modal from each FlatLists item. An item rendered as a TouchableHighlight should open the modal onPress and the modal should contain data from the item (in the code below this would be the items id). How can I achieve passing data to the modal? I somehow can't get it to work using nextProps. This seems more to be an issue related to setting state from within a FlatLists item rather than the Modal.
Modal:
export default class ModalView extends React.Component {
constructor() {
super();
this.state = {
modalVisible: false,
id: null,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
})
}
render() {
return (
<Modal
animationType="slide"
transparent={ true }
visible={ this.state.modalVisible }
onRequestClose={() => { this.props.setModalVisible(false) }}
>
<View>
<View>
<Text>{ this.state.id }</Text>
<TouchableHighlight
onPress={() => { this.props.setModalVisible(false) }}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
)
}
}
FlatList rendering TouchableHighlights:
export default class RecentList extends React.Component {
constructor() {
super();
this.state = {
modalVisible: false,
id: null,
}
}
_onPressItem(id) {
this.setState({
modalVisible: true,
id: id,
});
};
_renderItem = ({item}) => {
return (
<TouchableHighlight
id={item.id}
onPress={this._onPressItem}
>
<View>
<Text>{id}</Text>
</View>
</TouchableHighlight>
)
};
render() {
let data = realm.objects('Example').filtered('completed = true')
.sorted('startedAt', true).slice(0, 10)
return (
<View>
<ModalView
modalVisible={ this.state.modalVisible }
setModalVisible={ (vis) => { this.setModalVisible(vis) }}
id={ this.state.id }
/>
<FlatList
data={data}
renderItem={this._renderItem}
keyExtractor={(item, index) => index}
/>
</View>
)
}
}
A small mistake you have missed ...
_renderItem = ({item}) => {
return (
<TouchableHighlight
id={item.id}
onPress={() => this._onPressItem(item.id)} // Your not sending the item.id
>
<View>
<Text>{id}</Text>
</View>
</TouchableHighlight>
)
};

How refresh the ListView Component in react native?

I'm trying to create a todo list, then I'm trying to use this checkbox package
react-native-check-box
I don't know if this issue come from that package
when I click the checkbox and click the delete button this is what happen
And here is my code for displaying the list
interface TodoProps{
todo: TodoModel;
ter:string;
}
interface TodoState{
dataSource: any;
myTodo: Array<ITodo>;
}
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => true});
export default class Todo extends React.Component <TodoProps,TodoState>{
constructor(props:TodoProps) {
super(props);
this.state = {
dataSource: ds.cloneWithRows([]), // or put your initial data here
myTodo: []
};
}
componentWillReceiveProps = (nextProps) => {
console.log(this.state.myTodo);
let data = {
title: nextProps.ter,
isChecked: false
};
let todoList = this.state.myTodo;
if (nextProps.ter) {
todoList.push(data);
}
this.setState({
myTodo: todoList
});
}
onDelete(){
let todos = this.state.myTodo.filter((todo:ITodo) => {
return !todo.isChecked;
});
this.setState({
myTodo: todos
});
}
render() {
let dataSource = this.state.dataSource.cloneWithRows(this.state.myTodo);
return (
<View style={styles.container}>
<View style={styles.box2}>
<ListView enableEmptySections={true} dataSource={dataSource} renderRow={(rowData, sectionID, rowID) => <TodoList data={rowData} onClick={this.onClick.bind(this)} id={rowID} /> } />
</View>
<View style={styles.box3}>
<TouchableOpacity style={styles.bbox1} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>All</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox2} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>Complete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox3} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>InComplete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox4} onPress={()=> this.onDestroy()}>
<Text style={styles.tabText}>Delete</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
But if I console log the data. I find all isChecke: to false. Only the view of checkbox is not working. Do I need to use componentwillamount() for this?
Use the below sample code
_onRefresh() {
this.setState({refreshing: true});
// your callback function or call this.componentDidMount()
}
render() {
return (
<ListView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
...
>
...
</ListView>
);
}

Categories

Resources