search box function using redux in react native - react-native

I am trying to make a search in my db items but all I receive is the following error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Here is my code where I am creating the search page. JobItem I am using it in jobs page and everything is displaying correctly but here when I put the first letter in the search box I am getting the error.
import JobItem from './JobItem';
const { width, height } = Dimensions.get('window')
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = {
text: '',
data: ''
}
}
static navigationOptions = {
headerVisible: false
}
filter(text) {
const data = this.props.jobs;
console.log(data);
const newData = data.filter(function (job) {
const itemData = job.title.toUpperCase()
const textData = text.toUpperCase()
return itemData.indexOf(textData) > -1
})
this.setState({
data: newData,
text: text,
})
}
deleteData() {
this.setState({ text: '', data: '' })
}
_renderJobs(job) {
return this.props.jobs.map((job) => {
return (
<JobItem
key={job._id}
title={job.title}
shortDescription={job.shortDescription}
logo={job.avatar}
company={job.company}
id={job._id}
city={job.location[0].city}
postDate={job.postDate}
dispatch={this.props.dispatch}
onPress={() => this.onJobDetails(job)}
/>
)
})
}
render() {
const { goBack } = this.props.navigation
return (
<View style={styles.container}>
<View style={styles.header}>
<FontAwesome
name="magnify"
color="grey"
size={20}
style={styles.searchIcon}
/>
<TextInput
value={this.state.text}
onChangeText={(text) => this.filter(text)}
style={styles.input}
placeholder="Search"
placeholderTextColor="grey"
keyboardAppearance="dark"
autoFocus={true}
/>
{this.state.text ?
<TouchableWithoutFeedback onPress={() => this.deleteData()}>
<FontAwesome
name="clock-outline"
color="grey"
size={20}
style={styles.iconInputClose}
/>
</TouchableWithoutFeedback>
: null}
<TouchableWithoutFeedback style={styles.cancelButton} onPress={() => goBack()}>
<View style={styles.containerButton}>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableWithoutFeedback>
</View>
<ScrollView>
<FlatList
style={{ marginHorizontal: 5 }}
data={this.state.data}
numColumns={3}
columnWrapperStyle={{ marginTop: 5, marginLeft: 5 }}
renderItem={({ job }) => this._renderJobs(job)}
/>
</ScrollView>
</View>
)
}
}
Please anyone help me with this.

Related

React Native undefined is not an object (evaluating 'props.navigation.toggleDrawer')

I'm new to react native and so I'm wondering why I'm receiving an error like
"undefined is not an object (evaluating 'props.navigation.toggleDrawer')" when I try to click on hamburger menu in my Home
Here below my Home.js
const NavigatorHome = props => {
return (
<View>
<AppHeader navigation={props.navigation} title="Home" />
</View>
);
};
export default class Home extends Component {
state = {
users: []
}
async componentDidMount() {
const users = await ajax.fetchUsers();
//ET20200226 This was a warning
this.setState({users});
}
render() {
return (
<View>
<NavigatorHome></NavigatorHome>
<View>
<Text style={styles.h2text}>
List of requests
</Text>
<FlatList
data={this.state.users}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.flatview}>
<Text style={styles.uuid}>{item.uuid}</Text>
</View>
}
keyExtractor={item => item.uuid}
/>
</View>
</View>
);
}
}
Here my AppHeader.js
const AppHeader = props => {
return (
<Header
//leftComponent={<HamburgerMenu navigation={props.navigation} />}
leftComponent={<Icon
color="#fff"
name="menu"
onPress={() => props.navigation.toggleDrawer()}
/>}
centerComponent={{
text: props.title,
style: { color: "#fff", fontWeight: "bold" }
}}
statusBarProps={{ barStyle: "light-content" }}
/>
);
};
export default AppHeader;
Can someone help me to figure out how to fix it?
The reason for the error is that props.navigation is undefined in NavigatorHome. you must pass props.navigation to NavigatorHome. Your code should be as follows:
<View>
<NavigatorHome navigation={this.props.navigation}></NavigatorHome>
<View>

Implement onPress on Flatlist item

I am trying to send the data of the flatlist items when clicked and set to another class.The ontouch is working but I am having the error below in the image. Also how can I send the data of api to the other class and get from another class? I have implemented as follows:
export default class FlatSpeakers extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [],selectedItem: null, }
const { navigate } = this.props.navigation;
}
onPressItem = () => {
navigate('SpeakersClick')
};
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(res => {
this.setState({
isLoading: false,
data: res.data,
})
})
}
renderItem({ item }) {
return (
<TouchableOpacity onPress={()=>this.onPressItem(item)} >
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Image
style={styles.thumbnailStyle}
source={{ uri: item.image }}
/>
</View>
<View style={styles.headerContentStyle}>
<Text style={styles.headerTextStyle}>{item.title}</Text>
<Text>{item.artist}</Text>
</View>
</CardSection>
</Card>
</TouchableOpacity>
)
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
onPress={this.onPressItem}
/>
</View>
);
}
}
Problem in your code is, that you are calling same method from two sides - on one side you are passing arguments in it on another side you are not passing arguments. If you wan't to have both cases covered you should change you onPressFunction, to accept arguments - in your case item:
onPressItem = (item) => {
navigate('SpeakersClick')
};
try to put this.onPressItem = this.onPressItem.bind(this) on constructor(props)

Axios post with TextInput values not working with no trailing error

I am trying to pass some parameters from TextInput to the body in Axios. It doesn't display any error or return a status using console.log().
I have several ways to see what could have been the problem. I tried to pass the function to ComponentDiDMount and some other components lifecycles with no success. I have also passed the values directly, used Json.parse(), JSON.encode(), JSON.stringify(), no error and yet not returning status. I know there might be a mistake I am making.
More also, I don't know if I am doing this wrongly. I try to fetch data to a dropdown from which I need to use the key to pass the corresponding id of the selected value to category_id. When the page loads, it fetches "category" i.e a field name with corresponding id to the dropdown but only the corresponding is needed to pass to the Axios.post.
import React, { Component } from 'react';
import {
Text,
TextInput,
View,
Image,
TouchableOpacity,
Button,
StyleSheet} from 'react-native';
import { Dropdown } from 'react-native-material-dropdown';
import axios from 'axios';
export default class CreatePost extends Component {
constructor(props){
super(props)
this.state = {
category: [],
title: '',
cat: '',
author:'',
body:''
}
}
static navigationOptions = ()=> {
return{
title: null,
headerStyle: { backgroundColor: '#1A5276', color:'#fff' },
header:null
}
};
componentWillMount(){
axios.get(`http://localhost/rest_api_myblog/api/category/read.php`)
//.then(json => console.log(json.data.data[0].name))
.then(json => json.data.data)
.then(newData => this.setState({category: newData}))
.catch(error => alert(error))
}
onChangeTextPress(key, value){
this.setState((prevState) => {
//let selected = Object.assign({}, prevState.selected);
let selected = Object.assign({},prevState.selected);
selected[key] = value;
return { selected };
}, () => {
this.setState({ cat: this.state.selected[key]});
// console.log(cat);
});
}
onCreate = event => {
event.preventDefault();
const body = {
author :this.state.author,
title : this.state.title,
body : this.state.body,
category_id :this.state.cat
};
axios.post(`http://localhost/rest_api_myblog/api/post/create.php`, JSON.parse(body))
.then(res => {console.log(res)
})
.catch(e => console.log(e));
}
render() {
const data = this.state.category.map((cat, i) =>({
value: cat.name,
key: i
}));
return (
<View style= {styles.container}>
<View><Image style={styles.image} source={require('../images/blog.jpg')}/>
<Text style={styles.header}>Create Post</Text></View>
<View style={{alignItems:'center'}}>
<Text style= {styles.label}>Title</Text>
<TextInput
style={styles.textbox}
placeholder="Title"
onChangeText= {(title)=>{
this.setState({title});
}}
value={this.state.title}/>
<Text style= {styles.label}>Author</Text>
<TextInput
style={styles.textbox}
name='author'
placeholder="Author"
onChangeText= {(text)=>{
this.setState({author: text});
}}
value={this.state.author}
/>
<Text style= {styles.label}>Category</Text>
<Dropdown
dropdownOffset={{top:5, left: 0 }}
containerStyle={{
borderWidth:1,
borderColor:'lightgrey',
borderRadius:13, width:300, height: 40,
paddingLeft:6,
backgroundColor:'#fff'}}
rippleCentered={true}
inputContainerStyle={{ borderBottomColor: 'transparent' }}
data = {data}
valueExtractor={({value})=> value}
onChangeText={(value, key)=>{this.onChangeTextPress( value, key)}}
/>
<Text style= {styles.label}>Body</Text>
<TextInput
style={styles.textbox}
multiline = {true}
numberOfLines = {4}
placeholder="Body"
onChangeText= {(body)=>{
this.setState({body});
}}
value={this.state.body}
/>
<TouchableOpacity style={styles.buttonContainer}
onPress = {()=> {this.onCreate }}
>
<Text style={styles.buttonText}>Create</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
What I actually want is a post method based on the TextInput values entered by the users. More also, the corresponding ID of the selected dropdown value be passed instead of the actual value.
Thank you so much for your assistance.
From what I can read from the code, the problem seems to be in the way you call your onCreate method.
You are doing:
<TouchableOpacity style={styles.buttonContainer} onPress={()=> {this.onCreate }}>
<Text style={styles.buttonText}>Create</Text>
</TouchableOpacity>
Where you should be doing either:
<TouchableOpacity style={styles.buttonContainer} onPress={this.onCreate}>
<Text style={styles.buttonText}>Create</Text>
</TouchableOpacity>
Or:
<TouchableOpacity style={styles.buttonContainer} onPress={() => this.onCreate()}>
<Text style={styles.buttonText}>Create</Text>
</TouchableOpacity>

React Native FlatList Touchable Opacity

I used FlatList to display the title that is in the data. I added in TouchableOpacity for the FlatList. So for example, when I click 'First', I want to show the the data from 'mood' and it will show the list of passionate,rousing and confident. I want to show the list on a new file/screen and show purely the mood of list.
This is my data:
const Mock =
[
{ title: 'First',
mood:
[
{name: 'passionate'},
{name: 'rousing'},
{name: 'confident'},
],
},
{ title: 'Second',
mood:
[
{name: 'rollicking'},
{name: 'cheerful'},
{name: 'fun'},
{name: 'sweet'},
{name: 'amiable'},
{name: 'natured'}
],
This is my FlatList code:
export default class Cluster1 extends Component{
render() {
return (
<View>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
What should I do with the TouchableOpacity when I want to show the mood name when I click the title?
This is my style code
const styles = StyleSheet.create({
itemTitle:{
fontSize: 25,
fontWeight: 'bold',
color: 'white',
margin: 20,
},
},
list:{
flex: 1,
backgroundColor: '#00BCD4',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
},
});
You should modify your code as below to do this:
export default class Cluster1 extends Component {
render() {
return (
<View style={{ margin: 30, backgroundColor: '#ddd' }}>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
state = { showItemIndex: [false, false] };
_onPress = index => () => {
let showItemIndex = this.state.showItemIndex;
showItemIndex[index] = !this.state.showItemIndex[index];
this.setState({ showItemIndex });
};
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={this._onPress(this.props.index)}>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
{this.state.showItemIndex[this.props.index] && (
<FlatList
data={this.props.item.mood}
extraData={this.state.showItemIndex}
renderItem={({ item, index }) => {
return (
<Text item={item} index={index}>
{item.name}
</Text>
);
}}
/>
)}
</View>
</View>
);
}
}
Use this, it's should be work fine for you:
Link: https://github.com/oblador/react-native-collapsible
Link: https://github.com/naoufal/react-native-accordion
Link: https://github.com/cuiyueshuai/react-native-expandable-section-flatlist
You could set a state variable which gets updated whenever your TouchableOpacity gets pressed. And then you conditionally render the title or the list of mood names:
class FlatListItem extends Component {
constructor(props) {
super(props);
this.state = {collapsed: true}
}
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity
onPress={this.onPress}
>
<Text style={styles.itemTitle}>
{this.props.item.title}
</Text>
</TouchableOpacity>
{this.state.collapsed ?
<View /> :
<View>
{this.props.item.mood.map(mood => <Text>{mood.name}</Text>)}
</View>}
</View>
</View>
);
}
onPress = () => {
this.setState({collapsed: !this.state.collapsed})
}
}
You can do this by separating out the datasource that is required to show in the list.
First to display title: you can do something like this
export default class Cluster1 extends Component {
state = {
data: []
};
componentWillMount() {
const titles = Mock.forEach(data => data.title);
this.setState({
data: titles
});
}
onItemClick = item => {
const itemIndex = Mock.findIndex(data => (
data.title === item
));
const values = Mock[itemIndex].mood;
this.setState({
data: values
});
};
render() {
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item, index }) => {
return (
<FlatListItem
item={item}
index={index}
onItemClick={this.itemClick}
/>
);
}}
/>
</View>
);
}
}
and then in your FlatlistItem code:
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={() =>
this.props.onItemClick(this.props.item)
}>
<Text style={styles.itemTitle}>
{
this.props.item.name ?
this.props.item.name : this.props.item
}
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}

React navigation state.params not working

It is not working. I tried everything. Nothing works. state.params is simply not there if you make an advanced app.
I have this problem with the react "navigation". It says in the manual that the params object should be there https://reactnavigation.org/docs/navigation-prop.html#state-the-screen-s-current-state-route But it isn't.
I set an id parameter like this in screen 1 when I link to screen 2:
<TouchableWithoutFeedback onPress={ ()=> this.props.navigation.navigate('FontsTab', { id: item.id }) } style={styles.listHeader} >
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View style={styles.listContainer} onPress={(event) => this._selectedItem(item.text)} >
<Text style={styles.listHeader} >
{item.title}
</Text>
<Text style={styles.listValue} >{item.value}</Text>
<Image
style={{width: 50, height: 50}}
source={{uri: item.img}}
/>
</View>
</View>
</View>
</TouchableWithoutFeedback>
But it's not working. In screen 2 I can't use the state.params :
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props.navigation)}</Text>
<Text>TEST{ state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
state.params just returns nothing. What can I do about it?
The full class for screen2:
class Fonts extends Component {
constructor(props) {
super(props);
this.state = {
params: null,
selectedIndex: 0,
value: 0.5,
dataSource: null,
isLoading: true
};
this.componentDidMount = this.componentDidMount.bind(this);
}
getNavigationParams() {
return this.props.navigation.state.params || {}
}
componentDidMount(){
return fetch('http://www.koolbusiness.com/newvi/4580715507220480.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
...this.state,
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render() {
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props)}</Text>
<Text>TEST{ this.state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
);
}
}
In my app this pain is reproducible by a simple button in screen1:
<Button
onPress={() => navigate('FontsTab', { name: 'Brent' })}
title="Go to Brent's profile"
/>
Then switching to the FontsTab works but the params are not in the state object:
I also have this code for the tabview
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import FontsHome from '../views/fonts_home';
import FontsDetails from '../views/fonts_detail';
const FontsTabView = ({ navigation }) => (
<FontsHome banner="Fonts" navigation={navigation} />
);
const FontsDetailTabView = ({ navigation }) => (
<FontsDetails banner="Fonts Detail" navigation={navigation} />
);
const FontsTab = StackNavigator({
Home: {
screen: FontsTabView,
path: '/',
navigationOptions: ({ navigation }) => ({
title: '',
headerLeft: (
<Icon
name="menu"
size={30}
type="entypo"
style={{ paddingLeft: 10 }}
onPress={() => navigation.navigate('DrawerOpen')}
/>
),
}),
},
Detail: {
screen: FontsDetailTabView,
path: 'fonts_detail',
navigationOptions: {
title: 'Fonts Detail',
},
},
});
export default FontsTab;
this.props.navigation.state.params.id will give you the value of param id passed from screen1.
I put my screen in the right StackNavigator and then it worked.