In the following React-native code I have used native-base check box to functions to consider are _checkBox()
and _checkbox_check()
where i have used a state variable to hold the values whether they are checked or not in a state cb{}
on pressing the checkboxes i am able to change the values which i have checked using console.log()
in _checkbox_check()
function but the value for the same is not workinkg at checked={this.state.cb[data.id]}
which means the true and false in object cb corresponding to the keys of checkboxes are there but when its trues the checkboxes are checked,
while i have checked giving static values like checked={true}
which is working all fine.
please suggest if there is some mistake or chances of improvements code for my whole page is below
import React from "react";
import AsyncStorage from "@react-native-community/async-storage";
import {
Text,
View,
ScrollView,
Platform,
Image,
TouchableOpacity,
ToastAndroid,
StatusBar
} from "react-native";
import {
Content,
Container,
Button,
Icon,
Header,
Left,
Right,
Body,
Title,
Item,
Card,
CardItem,
DatePicker,
Label,
Input,
ListItem,
CheckBox
} from "native-base";
import Network from "../../network/network";
import LinearGradient from "react-native-linear-gradient";
import * as constant from "../../Constants/Constant";
const deviceHeight = constant.deviceHeight;
const deviceWidth = constant.deviceWidth;
import styles from "./Styles";
import Styles from "./Styles";
const icn = "../../Images/icons/blue/";
const platform = Platform.OS;
export default class SignInScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
services: null,
poolId: null,
chosenDate: new Date(),
choice: null,
description: null,
val: true,
cb: {}
};
this.setDate = this.setDate.bind(this);
}
setDate(newDate) {
this.setState({ chosenDate: newDate });
}
async componentWillMount() {
await Network.Token_get("apk/getServiceList", async response => {
if (response.status == true) {
await this.setState({
services: response.serviceData
});
}
});
}
componentDidMount() {
const { navigation } = this.props;
const itemId = navigation.getParam("id");
this.setState({
poolId: itemId
});
}
render() {
return (
<Container>
<Header
style={{
borderBottomWidth: 0,
justifyContent: "center",
alignItem: "center"
}}
>
<Left>
<Button
transparent
onPress={() => {
this.props.navigation.openDrawer();
}}
>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title style={styles.title}>Service Details</Title>
</Body>
<Right>
<Button transparent onPress={() => this._signOutAsync()}>
<Icon name="log-out" />
</Button>
</Right>
</Header>
<Content contentContainerStyle={styles.content} bounces={false}>
<ScrollView
contentContainerStyle={{
padding: 10,
alignItems: "flex-start",
justifyContent: "center",
backgroundColor: "#ffff",
shadowColor: "#1C0C59",
shadowOffsetWidth: 3,
shadowOffsetHeight: 3,
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 3,
borderRadius: 7,
bgColor: "#ffffff"
}}
>
<View
style={{ alignItems: "flex-start", justifyContent: "flex-start" }}
>
{this._checkBoxes()}
</View>
<View style={{ flexDirection: "row" }}>
<View>
<Text style={{ top: 10 }}>
Schedule Date:
{/* {this.state.chosenDate.toString().substr(4, 12)} */}
</Text>
</View>
<View>
<DatePicker
defaultDate={new Date(2018, 4, 4)}
minimumDate={new Date(2018, 1, 1)}
maximumDate={new Date(2018, 12, 31)}
locale={"en"}
timeZoneOffsetInMinutes={undefined}
modalTransparent={false}
animationType={"fade"}
androidMode={"default"}
placeHolderText="Select Schedule Date"
// textStyle={{ color: "green" }}
placeHolderTextStyle={{ color: "#d3d3d3" }}
onDateChange={this.setDate}
disabled={false}
/>
</View>
</View>
<Item floatingLabel style={{ marginTop: 20, marginBottom: 50 }}>
<Label>Description</Label>
<Input
multiline={true}
// style={{height:200, textColor: "#000"}}
style={{ color: "#000", height: 100 }}
onChangeText={description => this.setState({ description })}
/>
</Item>
<Button
rounded
primary
onPress={() => this._submit()}
style={{ paddingLeft: 18, alignSelf: "center" }}
>
<Text style={{ fontWeight: "600", color: "#000" }}>Submit</Text>
<Icon name="send" />
</Button>
</ScrollView>
</Content>
</Container>
);
}
mapPools(poolList) {
if (poolList) {
return poolList.map(data => {
return (
<Card style={{ borderRadius: 7 }}>
<CardItem style={{ borderRadius: 7 }}>
<TouchableOpacity>
<View style={styles.View_inside_card}>
<View style={styles.Incard_icon_View}>
<Image
source={require(icn + "swimmingPool.png")}
style={styles.Incard_icon}
/>
</View>
<View style={styles.Incard_Detail_View}>
<Text style={styles.Detail_name}>{data.pool_title}</Text>
<Text style={styles.Detail_name}>{data.address}</Text>
</View>
</View>
</TouchableOpacity>
</CardItem>
</Card>
);
});
}
}
_signOutAsync = async () => {
var loginid = await AsyncStorage.getItem("@LoginID");
payload = {
loginId: loginid
};
await Network.Token_put("apk/logout", payload, async response => {
ToastAndroid.show(response.message, ToastAndroid.SHORT);
if (response.status === true) {
await AsyncStorage.clear();
this.props.navigation.navigate("Auth");
}
});
// await AsyncStorage.clear();
// this.props.navigation.navigate("Auth");
};
_checkBoxes = () => {
if (this.state.services) {
return this.state.services.map(data => {
return (
<ListItem noBorder>
<CheckBox
checked={this.state.cb[data.id]}
onPress={() => this._chkbox_check(data.id)}
/>
<Text style={{ marginLeft: 20 }}>{data.services_title}</Text>
</ListItem>
);
});
}
};
_chkbox_check = param => {
console.log(param, this.state.cb);
if (this.state.cb.hasOwnProperty(param)) {
var element = this.state.cb[param];
console.log(element);
this.state.cb[param] = !element;
element = this.state.cb[param];
console.log(element);
} else {
this.state.cb[param] = true;
}
};
_submit = async sd => {
var payload = {
pool_id: this.state.poolId,
request_schedule_dateTime: this.state.chosenDate,
request_details: this.state.description,
service_type_id: this.state.choice
};
var url = "apk/createPoolRequest";
console.log("payload=>", payload);
await Network.Token_post(url, payload, async response => {
ToastAndroid.show(response.message, ToastAndroid.SHORT);
if (response.status === true) {
this.props.navigation.pop();
}
});
};
}
You should use setState
when modifying a component's state:
_chkbox_check = param => {
if (this.state.cb.hasOwnProperty(param)) {
var element = this.state.cb[param];
this.setState({
cb: {
...this.state.cb,
[param]: !element,
},
});
} else {
this.setState({
cb: {
...this.state.cb,
[param]: true,
},
});
}
}
According to the docs, modifying the state directly is a big no no. There are several reasons why, but the issue you're running in to is because of the fact that render()
will not be triggered until after setState()
is called.
In the code above setState
will only modify the cb
state, but since you don't want to completely overwrite cb
(since it stores the checked states for multiple checkboxes), you have to merge with the spread operator ...
, and access the dynamic key by wrapping it in square brackets []
.
Here's a working example stripped of all the irrelevant code:
import React from 'react';
import { View } from 'react-native';
import { ListItem, CheckBox } from 'native-base';
export default class SignInScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
cb: {}
};
}
render() {
return (
<View>
{this._checkBoxes()}
</View>
);
}
_checkBoxes = () => {
const services = [
{ id: 'service1' },
{ id: 'service2' },
{ id: 'service3' },
];
return services.map(data => {
return (
<ListItem noBorder>
<CheckBox
checked={this.state.cb[data.id]}
onPress={() => this._chkbox_check(data.id)}
/>
</ListItem>
);
});
}
_chkbox_check = param => {
if (this.state.cb.hasOwnProperty(param)) {
var element = this.state.cb[param];
this.setState({
cb: {
...this.state.cb,
[param]: !element,
},
});
} else {
this.setState({
cb: {
...this.state.cb,
[param]: true,
},
});
}
}
}
If you omit the line with ...this.state.cb
in setState
, then cb
will be completely overwritten with the new value.
For example, say you start with:
state.cb = { service1: true }
And then call _chkbox_check('service2');
, you'll get:
state.cb = { service2: true }
But with the spread operator you'll then get:
state.cb = { service1: true, service2: true }
SIDE NOTE
Your _chkbox_check
function can be simplified by not checking for the property in the state:
_chkbox_check = param => {
this.setState({
cb: {
...this.state.cb,
[param]: !this.state.cb[param],
},
});
}
This is because JS uses truthy values, so undefined
will be interpreted as false.