having a undefined value of object child from firebase - javascript

I'm very beginner in react native and I'm trying to develop a shopping app. When I tried to read the customers order from the db firebase, I cannot reach to the products and it shows me undefined.
This is my code
export default class Orders extends React.Component {
constructor(props) {
super(props);
this.state = {
arrData:[]
};
}
componentDidMount = () => {
var ref = database.ref('orders');
ref.once('value').then(snapshot => {
console.log('Orders',snapshot.val());
// get children as an array
var items = [];
snapshot.forEach((child) => {
items.push({
id: child.val().id,
customer: child.val().customerId,
products:JSON.stringify([child.val().products]),
});
});
this.setState({ arrData: items});
//console.log(items);
});
}
renderItem = ({item, index}) => (
<TouchableOpacity
style={styles.listItem}>
<View style={styles.view}>
<Text style={styles.text}>{item.customer}</Text>
</View>
</TouchableOpacity>
)
render()
{
return(
<View style={{flex: 1}}>
<FlatList
//refreshing={this.state.refresh}
//onRefresh={this.loadNew}
data={this.state.arrData}
keyExtractor={(item, index) => index.toString()}
style={{flex:1, backgroundColor:'#eee'}}
renderItem={this.renderItem}
//onEndReached={this.handleLoadMore}
onEndThreshold={0}
/>
</View>
)
}
}
I tried to change this line
var ref = database.ref('orders');
into this
var ref = database.ref('orders').child(myOrders);
but i get (null) in the console

Related

How to setState in different component React native?

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);
});
}

View not re-rendering after onPress

I'm trying to change the backgroundColor of a React Native Card component when onPress event is triggered. Although I'm seeing the change of the state on componentDidUpdate, I'm not visualising it.
I'm changing the value of the itemsPressed array when the onPress event is triggered. If the pressed item id is already in the array it removes it else it adds it into the array.
export default class Popular extends Component {
constructor(props) {
super(props);
this.togglePressed = this.togglePressed.bind(this);
this.state = {
categories: [],
itemsPressed: []
}
}
togglePressed = item => {
const id = item.id;
this.setState(({ itemsPressed }) => ({
itemsPressed: this.isItemPressed(item)
? itemsPressed.filter(a => a != id)
: [...itemsPressed, id],
}))
};
isItemPressed = item => {
const id = item.id;
return this.state.itemsPressed.includes(id);
};
componentDidMount() {
this.setState({
categories:this.props.categories,
});
}
componentDidUpdate(){
console.log(this.state.itemsPressed);
}
renderTabItem = ({ item,index }) => (
<TouchableOpacity
style={styles.category}
key={index}
onPress={() => this.togglePressed(item)}
>
<Card center
style={[styles.card,{backgroundColor:
this.isItemPressed(item)
? item.color
: 'gray'
}]}>
<Image source={item.icon} style={styles.categoryIcon}/>
</Card>
<Text size={12} center style={styles.categoryName}
medium color='black'
>
{item.name.toLowerCase()}
</Text>
</TouchableOpacity>
);
renderTab(){
const {categories} = this.state;
return (
<FlatList
horizontal = {true}
pagingEnabled = {true}
scrollEnabled = {true}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
snapToAlignment='center'
data={categories}
keyExtractor={(item) => `${item.id}`}
renderItem={this.renderTabItem}
/>
)
}
render() {
return (
<ScrollView>
{this.renderTab()}
</ScrollView>
);
}
}
I expected a visual change but I couldn't re render the renderTab().
Thank you!
Your FlatList has the property category as data source, so it only re-renders the cells if it detects a change in the category property. Your code however is only changing itemsPressed, so no cell is re-rendered.
You can tell the FlatList to listen for changes state.itemsPressed by specifying it in the extraData property:
extraData={this.state.itemsPressed}

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 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>
);
}

React native. losing context of this in touchable highlight on press.

I'm trying to add a TouchableHighlight component to a row in a list view.
The onPress function is throwing an undefined error in the code below. It works outside of the list view.
I suspect this is because I'm losing context of this but unsure how to fix. Anyone able to help?
export default class ConversationsList extends Component {
constructor(props) {
super(props);
this._handleChangePage = this._handleChangePage.bind(this);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(Coversations.chats)
};
}
_handleChangePage(chat) {
this.props.navigator.push({
title: 'foo',
component: Chat,
passProps: {
chat: chat
}
});
}
renderRow(chat){
return (
<View>
<TouchableHighlight onPress={ () => this._handleChangePage.bind(this, chat) }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</View>
);
}
}
I also suspect that I shouldn't really be doing things this way, that my component should be structured differently, so it is passed the press handler as a prop perhaps. any advice appreciated.
You can declare another variable globally like
var _this;
initialise it in render method
render:function(){
_this = this;
return(
...
)
}
and use it in your touchableHightlight
renderRow(chat){
return (
<View>
<TouchableHighlight onPress={ () => _this._handleChangePage(chat) }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
I suggest to read this helpful article
export default class ConversationsList extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(Coversations.chats)
};
}
_handleChangePage = () => {
this.props.navigator.push({
title: 'foo',
component: Chat,
passProps: {
chat: this
}
});
}
renderRow = (chat) => {
return (
<View>
<TouchableHighlight onPress={ this._handleChangePage }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</View>
);
}
}

Categories

Resources