I want to build a search bar that filters a flatlist in react native. I'm doing so with a TextInput and a component SearchFilter.
In my homescreen I have this TextInput:
<TextInput
value={input}
onChangeText={(text) => setInput(text)}
style={{ fontSize: 16, marginLeft: 10 }}
placeholder="Search"
/>
And this component:
<SearchFilter data={Cars} input={input} setInput={setInput} />
In the component file I have my flatlist:
const searchFilter = (data, input, setInput) => {
console.log(input)
return (
<View>
<Text>SearchFilter</Text>
<FlatList
style={styles.list}
data={data}
renderItem={({ item }) => {
if (input === "") {
return (
<View>
<Text>test</Text>
</View>
)
}
}}
></FlatList>
</View>
);
};
When nothing is being searched I want test to be displayed.
The problem is that it shows nothing.
When I do a console.log(input) in my homescreen the console returns an emty string
but when I do a console.log(input) in my component file it returns {}. I do not know why. When I tried
if (input === " {}") {
return (
<View>
<Text>test</Text>
</View>
)
}
it also did not work.
Any asolutions?
I suppose the searchFilter is your component ?
If it is the case then you don't use the props correctly, try like this :
const SearchFilter = ({data, input, setInput}) => { ... rest of your code ... }
You can't compare a object like this, it's not the same (in the memory).
Assuming var x = {}
x == {} // false (it's the same 'content' but it's not saved at the same place in the memory
x == "{}" // false (x is a object "{}" is a string)`
Assuming var y = x
y == x // true
To compare basic object, you can use JSON.stringify() function, it's parse object to string like this : (JSON.stringify(x) == JSON.stringify({})) === true
It's explain why your condition doesn't work but I don't know why do you have a object as output (I'm not a react developer ^^)
I hope it's even be usefull for you
Related
I'm trying to render multiple components via FlatList but i get this error : "Warning: Each child in a list should have a unique "key" prop."
I made sure the keyExtractor property was set up correctly but i believe my issue happened when trying to render multiple components inside my FlatList with map.
My FlatList and custom component looks like so :
const ItemView = (row: any) => {
let title = row.item.title
let split = title.split(search)
let searchStringCount = split.length
return (
<Text>
{
split.map((elem: string, index: number) => {
return (
<>
<Text style={styles.textListStyle}>
{elem}
</Text>
{index + 1 < searchStringCount &&
<Text style={styles.textHighLightStyle}>
{search}
</Text>}
</>
)
})
}
</Text>)
}
<FlatList
style={styles.itemStyle}
data={filteredData}
keyExtractor={(item, index) => {
return index.toString();
}}
ItemSeparatorComponent={ItemSeparatorView}
renderItem={ItemView} />
I've tried in vain inserting manually a key property to the generated Text components.
you need to add key prop when render with map
split.map((elem: string, index: number) => {
return (
<View key={index}>
<Text style={styles.textListStyle}>
{elem}
</Text>
{index + 1 < searchStringCount &&
<Text style={styles.textHighLightStyle}>
{search}
</Text>}
</View>
)
})
How to get values from multiple TextInput fields coming from array passing by map function to single variable by entering text in them? When i try to enter text in second TextInput it replaces the value which i stored from first TextInput.
Secondly instead of this, if i use push() function, it doesn't give desired output. What I exactly want is that to get the values of these three InputText and to store in single variable using single OnChangeEvent (as I am using Map() function).
Below is the sample of code on which i am working in React-Native.
this.state={
checkboxAttCollection:[{"Id": 10, "AttibuteCollectionName": "PowerTest"}, {"Id": 22, "AttibuteCollectionName": "36W"}, {"Id": 23, "AttibuteCollectionName": "Test123"}],
getInputText:'',
getInputvariables:[],
onChangeTextComp=(TextValue,index)=>{
this.state.getInputText=TextValue
console.log("******",this.state.getInputvariables)
this.state.getInputvariables.push(this.state.getInputText)
console.log("******",this.state.getInputvariables)
{this.state.checkboxAttCollection.map((item, i) =>
return (<View key={item.AttibuteCollectionId} style={{ flexDirection: 'row',}}>
<TextInput style={{height:hp('5%'),width:wp('60%'),backgroundColor:'red',borderBottomWidth:2,paddingVertical:0}}
onChangeText={(text)=>this.onChangeTextComp(text,i)}
MultiInputText={true}/>
{/* </View> */}
</View>)
})}
Try this way
this.state={
......
inputVlaues: []
}
onChangeTextComp=(value,index)=>{
const inputData = [...this.state.inputVlaues];
inputData[index] = value;
this.setState(inputVlaues: inputData);
}
{this.state.checkboxAttCollection.map((item, i) =>
return
(<View key={item.AttibuteCollectionId} style={{ flexDirection: 'row',}}>
<TextInput
onChangeText={(text)=>this.onChangeTextComp(text,i)}
......
value={this.state.inputVlaues[i] || ""}
/>
</View>)
})}
as an option you can generate event handlers dynamically
const [form, setForm] = useState({})
const createHandler = (fieldName) => {
return (newFieldValue) => {
setForm((oldValue) => {
return {
...oldValue,
[fieldName]: newFieldValue
}
})
}
}
return (
<>
<TextInput onChange={createHandler('name')} />
<TextInput onChange={createHandler('surname')} />
</>
)
I have a FlatList with about 60 items.
Each item has a small button that is clicked to display more information inside the FlatList item.
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo() }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo ? <View><Text>{ itemData.item.info }</Text><View> : null }
The onPress toggle function is something like:
const toggleInfo = () => {
if (showInfo === true) {
setShowInfo(false);
} else {
setShowInfo(true);
}
};
Of course, since it's a FlatList, when I click the button all of the FlatList items show their hidden contents. But I only want the info for the clicked item to show, leaving all the others unchanged.
So, I changed the onPress to take an argument:
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
...which is fine. But now I need to target the right state array (which is the same as the id but with an "z" tacked on the end to avoid any variable conflicts):
const toggleInfo =(id) => { // id might be "ABC"
const infoState = `${id}z`;
const infoStateSET = `set${speciesState}`; // therefore: setABCz
// Now I want to target the state "ABCz" and "setABCz" useState variables
if (infoState === true) {
infoStateSET(false);
} else {
infoStateSET(true);
}
};
Now, obviously there is no literal "infoStateSET" to change the state but I do want to use the variable to target the set state function.
Is this possible?
You can just set the id in showInfo state and then check if showInfo id is the same as the itemData.item.id.
basically you would have a state like this.
const [showInfo, setShowInfo] = useState(null);
Then you would set the state like so using your toggleInfo function:
const toggleInfo = (id) => {
if (showInfo === id) {
setShowInfo(id);
} else {
setShowInfo(null);
}
}
Then in your Flatlist item:
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo === itemData.item.id ? <View><Text>{ itemData.item.info }</Text><View> : null }
I'm creating an APP that get some data from fetch function. No problem here. The array has the data correctly. I'm doing it like this:
constructor(){
super()
this.state = {
fetching: false,
api: []
}
}
componentWillMount(){
this.setState({ fetching: true })
api.getMonuments().then(res => {
this.setState({
api: res,
fetching: false
})
})
}
I got this data: an array of 4 objects
Then I want to pass that data to another scene. I'm doing it like this:
<View style={styles.contentContainer}>
<TouchableHighlight
style={[styles.button, {marginBottom:0}]}
onPress={() => navigate('Monumento', this.state.api)}
underlayColor='#000'
>
<View style={styles.buttonContent}>
<Animatable.Text
style={styles.buttonText}
animation="bounceInLeft"
duration={1500}
>
Click here!
</Animatable.Text>
</View>
</TouchableHighlight>
</View>
On the other scene I get that data with the navigation.state.params but the problem now is that there is no more an array with 4 objects in it, but instead there is an object that have 4 objects in it...if I console log the data that is what's appears
render(){
const api = this.props.navigation.state.params;
console.log('API:', api)
...
Now I want to use the map function but I can't because 'api' is not a function...How can I workaround this?
render(){
var api={"bar":"nihao"};
return(
<View>
{Object.entries(api).map(([key,v])=>{
return <View key={key}><Text>{v}</Text></View>
})}
</View>
)
}
api is a single object not array.
api is a array.
render(){
var api=[{"bar":"nihao"},{"bar":"nihao2"},{"bar":"nihao3"}];
return(
<View>
{api.map((v,index)=>{
return <View key={index}><Text>{v.bar}</Text></View>
})}
</View>
)
}
You can use Object.entries with RN for mapping the key/value pairs of an object. Eg:
const api = { 'foo': 'bar', 'foz': 'baz'};
...
render() {
return (
Object.entries(api).map(([key, value]) => {
return <View key={key}>{value}</View>
});
)
}
The issue is you are accessing params object, but what you want is api array. I guess you are using react navigation. If so, then your call to navigate function should be like this:
navigate('Monumento', {api: this.state.api}).
And you can retrieve it like this:
this.props.navigation.state.params.api.
Navigate function takes screen name and params object.
Read this: https://reactnavigation.org/docs/navigators/navigation-prop#navigate-Link-to-other-screens
I am trying to loop through this array and print out the quote, depending on if it is saved as true or false.
At the moment, it just prints out in the JSON array. I'm new to react native, so not 100% certain of the behaviour of map.
var savedQuote = quotes.quotesArray.map(quote => quote.isSaved)
{
quotes.quotesArray.map((quote, i) => {
if(savedQuote){
return(
<TouchableOpacity key={i} style = {styles.border}>
<Text style = {styles.text}>
i: {i}. {quotes.quotesArray[i].preview}
</Text>
</TouchableOpacity>
)
}
else{
return <Text key = {i}>{i}Nada</Text>
}
})
}
I don't understand why you have two map in your code. One should suffice :
quotes.quotesArray.map((quote, i) => {
if(quote.isSaved){
return(
<TouchableOpacity key={i} style = {styles.border}>
<Text style = {styles.text}>
i: {i}. {quote.preview}
</Text>
</TouchableOpacity>
)
} else {
return <Text key = {i}>{i}Nada</Text>
}
});
This will loop through quotes and either return one node or the either if quote.isSaved is true or not.
you could save them to a new array if you assign it to a new variable ex: var savedQuotes = ... or use it inside your render function :
render() {
return (
<View>
{quotes.quotesArray.map...}
</View>
);
}
The map() method creates a new array with the results of calling a
provided function on every element in this array.
Here is more information: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Here are some examples from the react documentation : https://facebook.github.io/react/docs/lists-and-keys.html (which should be close enough to react-native)