Multiple switches enable all at once when generated from array react-native - react-native

What would you do to just enable the one switch (toggle) the user wishes to enable?
Here is my state:
state = {
menuItems: [
{ title: 'Test1', switchValue: false },
{ title: 'Test2', switchValue: false }
]};
Here is my constructor:
constructor(props: any) {
super(props);
this.toggle = this.toggle.bind(this);
}
And here is function control toggle:
toggle(item: any) {
const menu = [...this.state.menuItems];
menu[item].switchValue = !menu[item].switchValue;
this.setState({ menu });
}
And here is the map look like that:
public render() {
return (
<View style={styles.container}>
{this.state.menuItems.map((item, index) => (
<TouchableOpacity onPress={this.showSettingHint} key={item.title}>
<View style={[styles.rowContainer, index === 0 ? styles.topRowContainer : null]}>
<Text style={styles.title}>{item.title}</Text>
<Switch
onValueChange={this.toggle}
value={item.switchValue}
/>
</View>
</TouchableOpacity>
))}
</View>
);}
But I got an error like this:
undefined is not an object (evaluating 'menu[item].switchValue')

It may be that the toggle function expects an index for the menu item as an argument.
toggle(item: any) {
const menu = [...this.state.menuItems];
menu[item].switchValue = !menu[item].switchValue;
this.setState({ menu });
}
And in your Switch you are not passing the index of the menu item then, I think it would work if you pass the index in the onValueChange like so:
<Switch
//Add index here
onValueChange={this.toggle(index)}
value={item.switchValue}
/>

Related

Replace item in array react native

I'm new to js and react-native.
I have buttons on my app to change the languages, one button "English" and one button "Français".
const langues = [
{
id:0,
title: 'Français',
selected: true
},
{
id:1,
title: 'English',
selected: false
}
];
function Settings() {
return(
<View>
{langues.map(({title,selected}) => (
<View>
<Pressable style={styles.LanguesButton} >
{selected && <AntDesign size={15} name={'checkcircle'} /> }
<Text style={ {paddingLeft:selected ? 15 : 30} }>{title}</Text>
</Pressable>
</View>
))}
</View>
)
}
I would like to set selected to true for English, and false for Français when I click on "English" and same for "Français" but I don't understand how to do that.
PS: I already see that there are similar topics here but like I said I'm new to this language and I didn't understand the explanation on those topics ^^'.
First you need to create a state object that tells react native to render whenever it is updated like so;
import { useState } from "react";
const [languages, setLanguages] = useState([
{
id: 0,
title: 'Français',
selected: true
},
{
id: 1,
title: 'English',
selected: false
}
]);
Then you render this list. Whenever you press any language, you modify the state by calling setLanguages function like so;
const onPressed = (title) => {
let temp = [...languages];
temp.forEach(lang => {
if (lang.title == title) {
lang.selected = true;
}
else {
lang.selected = false;
}
});
setLanguages(temp);
}
function Settings() {
return (
<View>
{languages.map(({ title, selected }) => (
<View>
<Pressable style={styles.LanguesButton} onPress={() => {
onPressed(title);
}}>
</Pressable>
</View>
))}
</View>
)
}
After every press you will set the state and the screen will know that there has been a change and rerender.
Through onPress and find, like:
<Pressable onPress={ () =>
langues.find(lang.title === title).selected = true}>
https://reactnative.dev/docs/pressable#onpress

props.onClick undefined checkbox React Native

I am using the Checkbox component for my code and I have a list of elements and for each element I have a checkbox. However, my checkbox returns the following error when I check it on the phone simulator :
TypeError: this.props.onClick is not a function. (In 'this.props.onClick()', 'this.props.onClick' is undefined)
I don't understand because a checkbox does not require the onClick function ...
Please see my code below if needed:
import CheckBox from 'react-native-check-box'
export default class List extends Component {
constructor(props) {
super(props)
this.state = {
names: [
{
key: 0,
name: 'Element1',
isChecked: false
},
{
key: 1,
name: 'Element2',
isChecked: false,
}
]
}
}
checkboxTest(key){
let names = this.state.names.reduce((acc,name)=>{
if(name.key === key){
return {...name, isChecked: !name.isChecked}
}
return name
}, [])
this.setState({names})
console.table(names)
}
render(){
return (
<ScrollView>
<View>
{
this.state.names.map((item) => (
<View style={styles.background}>
<Text style = {styles.title}>{item.name}</Text>
<CheckBox value={false} onChange={()=>this.checkboxTest(item.key)}/>
</View>
))
}
</View>
</ScrollView>
)
}
}
If you read the documentation carefully, you will noticed that this checkbox component requires a onClick function, which you did not provide. Hence, instead of writing onChange, you should be using onClick instead
<CheckBox
style={{flex: 1, padding: 10}}
onClick={()=>{
this.setState({
isChecked:!this.state.isChecked
})
}}
isChecked={this.state.isChecked}
leftText={"CheckBox"}
/>
According to react-native-check-box documentation prop onClick is isRequired. But you are passing onChange not onClick.
Change your onChange to onClick in order to fix the error. Also change value to isChecked.
<CheckBox isChecked={false} onClick={()=>this.checkboxTest(item.key)}/>
Edit
Check below complete example for information
import * as React from "react";
import { Text, View } from "react-native";
import CheckBox from "react-native-check-box";
export default class List extends React.Component {
constructor(props) {
super(props);
this.state = {
names: [
{
key: 0,
name: "Element1",
isChecked: false
},
{
key: 1,
name: "Element2",
isChecked: false
}
]
};
}
checkboxTest = key => {
let names = this.state.names.reduce((acc, name) => {
if (name.key === key) {
acc.push({ ...name, isChecked: !name.isChecked });
} else {
acc.push(name);
}
return acc;
}, []);
this.setState({ names });
};
render() {
return (
<View>
{this.state.names.map((item, index) => (
<View style={{ flexDirection: " row" }}>
<Text>{item.name}</Text>
<CheckBox
isChecked={
this.state.names.find(item => item.key == index).isChecked
}
onClick={() => this.checkboxTest(item.key)}
/>
</View>
))}
</View>
);
}
}
Hope this helps you. Feel free for doubts.

Redux reducer not changing prop

I am making a todo list application with redux. I am able to add todos perfectly fine with redux however my toggle todos and remove todos are having problems.
The toggle todo action gets called by the redux store (I see it happening in the debugger), however, it does not update the prop to be the opposite of completed and I am not sure why.
I have tried playing around with the syntax and modeling other people's redux todo lists for hours but have not been able to solve this issue.
My toggleTodo and removeTodo actions:
export const toggleTodo = (item) => {
return {
type: TOGGLE_TODO,
id: item.id
};
};
export const removeTodo = (item) => {
return {
type: REMOVE_TODO,
id: item.id
};
};
My TodoReducer: // this is where I suspect the problem is
const initialState = {
todos: []
};
const todos = (state = initialState, action) => {
switch (action.type) {
case TOGGLE_TODO:
if (state.id !== action.id) {
return state;
}
return {
...state, completed: !state.todos.completed
};
case REMOVE_TODO: {
const newState = [...state];
newState.splice(action.id, 1);
return { ...newState };
}
My main flatlist where I call the actions:
render() {
return (
<View style={{ height: HEIGHT }}>
<FlatList
data={this.props.todos}
extraData={this.state}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => {
return (
<TodoItem
todoItem={item}
pressToToggle={() => this.props.toggleTodo(item)}
deleteTodo={() => this.props.removeTodo(item)}
/>
);
}}
/>
</View>
);
}
}
export default connect(mapStateToProps, { addTodo, toggleTodo, removeTodo })(MainTodo);
// I call the actions I am using here and don't use mapDispatchToProps
And my TodoItem component where I pass in the props:
class TodoItem extends Component {
render() {
const todoItem = this.props.todoItem;
return (
<View>
<TouchableOpacity
style={styles.todoItem}
onPress={this.props.pressToToggle}
>
<Text
style={{
color: todoItem.completed ? '#aaaaaa' : '#f5f5f5',
textDecorationLine: todoItem.completed ? 'line-through' : 'none',
fontSize: 16 }}
>
{todoItem.text}
</Text>
<Button
title='Remove'
color='#ff5330'
onPress={this.props.deleteTodo}
/>
</TouchableOpacity>
</View>
);
}
}
When I hit toggle todo instead of the prop changing and the line coming through over the text nothing happens.
And when I try to remove a todo I get this error- "invalid attempt to spread non-iterable instance."
when you pass a function to component, try to pass it's reference, instead of
<TodoItem
todoItem={item}
pressToToggle={() => this.props.toggleTodo(item)}
deleteTodo={() => this.props.removeTodo(item)}
/>
try
<TodoItem
todoItem={item}
pressToToggle={this.props.toggleTodo.bind(this)}
deleteTodo={this.props.removeTodo.bind(this)}
/>
and in your TodoItem component call the function like
class TodoItem extends Component {
render() {
const todoItem = this.props.todoItem;
return (
<View>
<TouchableOpacity
style={styles.todoItem}
onPress={() => this.props.pressToToggle(todoItem)} /* this line */
>
<Text
style={{
color: todoItem.completed ? '#aaaaaa' : '#f5f5f5',
textDecorationLine: todoItem.completed ? 'line-through' : 'none',
fontSize: 16 }}
>
{todoItem.text}
</Text>
<Button
title='Remove'
color='#ff5330'
onPress={this.props.deleteTodo}
/>
</TouchableOpacity>
</View>
);
}
}

React-Native-Component not rendering when state is changed

I am making the show more and show less functionality inside a flat list but the state pressed is not working as expected .When I am setting the state value component is not being rendered when the state changes its value.
My constructor is set like below
this.state = {
accList: [],
expanded: false,
expandedText: "Show More"
}
In componentdidmount() I am updating the value of accList value like below
componentDidMount = () => {
this.setState({
accList:[{
"customer_name": "Shubhangi J Thakur",
"message":"Hello"
},
{
"customer_name": "Arthur S Campbell",
"message":"Hello_World"
},
{
"customer_name": "Susan R Brill",
"message":"hellow"
}]
});
}
I have defined the flatlist in render() like below
<FlatList
onScroll={this.handleScroll}
data={this.state.accList}
renderItem={this.renderItem}
keyExtractor={this._keyExtractor}
/>
renderItem = ({ item, index }) => (
<Card style={style.cardLayout} key={index}>
<CardItem header>
<Text>{item.customer_name}</Text>
</CardItem>
{this.seemorefunctionality(item)}
</Card>
);
seemorefunctionality = (item) => {
return <View>
{this.state.expanded ? this.expandedView(item) :null}
//To view Show More and Show Less Text
<TouchableOpacity onPress={this.expandedText}>
<Text> {this.state.expandedText}</Text>
</TouchableOpacity>
</View>
}
}
expandedText = () => {
console.log('Setting the expanded text value', this.state.expanded)
if (this.state.expanded) {
this.setState({
expandedText: "Show More"
});
}
else {
this.setState({
expandedText: "Show Less"
});
}
value=!this.state.expanded
this.setState({
expanded: value
});
}
expandedView = (item) => {
return <View>
{item.map((obj, index) => {
return (
<View key={index} >
<Text>{obj.message}</Text>
</View>
)
})}
</View>
When I am clicking on the this.state.expandedText value is getting changed when we see in the console but its not reflecting in the View also expandedView is not being rendered when this.state.expanded is set to true.
In View the value of this.state.expandedText is always showing Show More while I can see In console that the value is getting changed to Show more and Show Less on click
for re-rendering flatlist you have to add extraData={this.state} as mention on https://facebook.github.io/react-native/docs/flatlist

React Native onPress active state change image source on Carousel

Trying to change image of a button on my carousel elements, currently it (below code) changes all the images when I click any of them. I'd like change that only current carousel's image. Any ideas? Thanks
class CarouselImages extends React.Component {
constructor(props) {
super(props);
this.state = {
myImagesArray: [
{
key: 1,
title: 'Category'
},
{
key: 2,
title: 'Category'
},
{
key: 3,
title: 'Category'
}
],
icon_active: false,
}
activateCarouselButton = a => {
const newState = Object.assign(
{},
{
icon_active: false,
},
{ [a]: true },
)
this.setState(newState);
}
}
render = () => {
const { icon_active } = this.state;
var myCarousel = this.state.myImagesArray.map(function (index) {
return (
<View key={index}>
<TouchableHighlight onPress={() => activateCarouselButton('icon_active')} >
<Image
source={icon_active ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
);
});
return (
<View>
<Carousel
style={{ backgroundColor: '#fff' }}>
{myCarousel}
</Carousel>
</View>
)
}
}
You need to hold key of the icon in the icon_active state, not a boolean. This gives you a hunch on how to do it:
render() {
const { icon_active } = this.state;
return (
this.state.myImagesArray.map((image) => {
return (
<View key={image.key}>
<TouchableHighlight onPress={() => activateCarouselButton(image.key)}>
<Image source={icon_active === image.key ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
)
})
)
}
<Image source={this.props.secureTextEntry ?
require('../../assets/images/signup/Showpassword.png') :
require('../../assets/images/signup/Hidepassword.png')} />