React Native - Trying to print depending on the state of index - react-native

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)

Related

My if statement is not working in React Native

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

React Native FlatList key with multiple rendering

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

React Native : replace a string with a Text component

I am trying to convert some homemade tags/bbcode and for doing so I need in some case not to return a string but a text component, I am trying to do that with this small function but the issue is that when I render it it display [object Object] instead of the component.
helper.js
import { Text } from "react-native";
const decodeTags = (string) => {
string = string.replace(
/\[b\](.+)\[\/b\]/isu,
<Text style={{ fontWeight: "bold" }}>$1</Text>
);
profilBio.js
<Text style={styles.bio}>
{decodeTags(props.profil.bio)}
</Text>
Render
[object Object] (instead of some text with a part in bold)
If the request is how to update styles conditionally;
To update styles conditionally;
<Text style={(this.state.myCondition == true) ? styles.bio_font_weight : styles.bio}>{decodeTags(props.profil.bio)}</Text>
And update decodeTags() to return only the data, not a Text component.
You'll need some pre-processor function which would basically split the string at the string which you need to make bold. After that, just basic string substring operation and concatenating the parts.
Ex:
const highlightKeyword = useCallback((originalString = '', searchQuery) => {
let s = originalString;
let searchStartIndex = s.indexOf(searchQuery);
return (
<Text>
<Text style={Styles.text}>{s.substr(0, searchStartIndex)}</Text>
<Text style={[Styles.text, {color: Colors.RED}]}>{searchQuery}</Text>
<Text style={Styles.text}>
{s.substr(searchStartIndex + searchQuery.length, s.length)}
</Text>
</Text>
);
}, []);
highlightKeyword(props.profil.bio,searchQuery)

Toggle a button selection on same and others in React (Javascript)?

I have a form with a question and 3 answers. Only one answer can be selected so I need to toggle each answer individually AND toggle between the 3.
I put an incoming array of objects into state on component load and iterate over that data. I add in a selected key to each object of the array with boolean which will be deleted before form submit.
Right now the behavior is that I'm able to toggle the same button but clicking another does change the previous selected but have to click again to select the new current. Obviously one crucial set is missing but not sure if I should set up a new state or if it can be done with the current config. Basically, the buttons should behave like checkboxes.
The code:
const answers = ['Frequency', 'Some Times', 'Hardly Ever'] // predefined
const ChecklistModal = ({ setShowModal, checklist }: any) => {
const [updatedList, setUpdatedList] = useState(
checklist.list.map((c) => ({
...c,
selected: !!c.answer, // added key with truthy value based on already chosen from
// backend or selected in form (frontend)
})),
)
// where the magic happens
const handleAnswer = (
answer: string,
questionId: number,
listIdx: number,
) => {
const listCopy = [...updatedList]
const list = listCopy[listIdx]
list.question = questionId
list.answer = answer
list.selected = !list.selected
listCopy[listIdx] = list
setUpdatedList(listCopy)
}
return (
<Modal>
<View style={[styles.container, containerByDevice]}>
// relevant code
{checklist.list.map((li, index) => (
<View key={li.question.id}>
<Text style={styles.questionText}>{li.question.title}</Text>
<View style={styles.answerRow}>
{answers.map((answer) => (
<View
key={answer}
style={
updatedList[index].selected &&
updatedList[index].answer === answer
? styles.selectedAnswerButton
: styles.answerButton
}
>
<TouchableOpacity
onPress={() => {
handleAnswer(answer, li.question.id, index)
}}
>
<Text>{answer}</Text>
</TouchableOpacity>
</View>
))}
</View>
</View>
))}
</View>
</Modal>
)
}
export default ChecklistModal
The initial checklist data looks like this:
checklist {
concern {
title
}
list {
question {
id
title
}
answer
}
}
}
}
`
You'll need to create another state which will store the selected answer and then add modify your condition like this: -
// state to store the selected answer
const [selectedAnswer, answer]= useState('');
// modify your condition
<View
key={answer}
style={
updatedList[index].selected &&
selectedAnswer == answer && // <== Add this condition
updatedList[index].answer === answer
? styles.selectedAnswerButton
: styles.answerButton
}
>
<TouchableOpacity
onPress={() => {
handleAnswer(answer, li.question.id, index)
}}
>
<Text>{answer}</Text>
</TouchableOpacity>
</View>
Also i have created a snack for your reference :- https://snack.expo.dev/#arjunshukla97/toggleanswer

how to use if condition in .map function?

Hi, I used if condition like below, but there is nothing rendering on the screen. By the way, there is 'MAVI' in leader array
renderall() {
return this.state.leader.map(alb => {
if(alb.Renk == 'MAVI') {
<View style={styles.container} key={counter = counter + 1}>
<Text style={[styles.textStyle, {marginLeft:'5%'}]}> {alb.Tescil_No} </Text>
<Text style={[styles.textStyle, {marginLeft:'6%'}]}> {alb.GumrukAdi} </Text>
<Text style={[styles.textStyle, { marginLeft:'5%'}]}> {alb.ACIKLAMA} </Text>
</View>
}
});
}
You're missing a return in your .map. Notice that inside the if statement I am returning the items being mapped.
renderall() {
return this.state.leader.map(alb => {
if(alb.Renk == 'MAVI') {
return (
<View style={styles.container} key={counter = counter + 1}>
<Text style={[styles.textStyle, {marginLeft:'5%'}]}> {alb.Tescil_No} </Text>
<Text style={[styles.textStyle, {marginLeft:'6%'}]}> {alb.GumrukAdi} </Text>
<Text style={[styles.textStyle, { marginLeft:'5%'}]}> {alb.ACIKLAMA} </Text>
</View>
);
}
});
}
This article explains in more detail how the .map function works
https://codeburst.io/learn-understand-javascripts-map-function-ffc059264783
Here is a very small example showing how to use the .map function. Notice the return statement.
let leaders = ['Tom','Jerry','Mike'];
let mappedLeaders = leaders.map((leader, index) => {
return `${leader} is number ${index}`; // notice that I am returning here
})
console.log(mappedLeaders)
Here is an example of using a .map with an if statement inside it. Notice we will get undefined for the first item in the mappedLeaders as we are not returning anything for the first item because Tom is excluded due to the fact that his name is too short.
let leaders = ['Tom','Jerry','Mike'];
let mappedLeaders = leaders.map((leader, index) => {
if (leader.length > 3) {
return `${leader} is number ${index}`; // notice that I am returning here
}
});
console.log(mappedLeaders)