在下面的React-native代码中,我使用了基于本机的复选框来考虑的功能是 _checkBox()
和_checkbox_check()
在这里我使用状态变量来保存值,无论它们是否处于cb{}
状态
在按下复选框时,我可以更改在console.log()
函数中使用_checkbox_check()
检查的值,但是在checked={this.state.cb[data.id]}
上不能使用该值,这意味着对应于复选框键的对象cb中存在false和false,但是当复选框为true时,
而我已经检查过给定静态值,例如checked={true}
了,就可以了。
请建议是否存在一些错误或改进的机会 整个页面的代码如下
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();
}
});
};
}
答案 0 :(得分:2)
修改组件状态时,应使用setState
:
_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,
},
});
}
}
根据文档,直接修改状态是不行的。造成这种情况的原因有多种,但您遇到的问题是由于在调用render()
之后才触发setState()
。
在setState
上方的代码中,只会修改cb
状态,但是由于您不想完全覆盖cb
(因为它存储了多个复选框的选中状态),您必须与spread operator ...
合并,并通过将其包装在方括号[]
中来访问dynamic key。
这是一个去除所有不相关代码的工作示例:
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,
},
});
}
}
}
如果您在...this.state.cb
中省略了带有setState
的行,那么cb
将被新值完全覆盖。
例如,假设您开始于:
state.cb = { service1: true }
然后致电_chkbox_check('service2');
,您将获得:
state.cb = { service2: true }
但是使用传播算子,您将得到:
state.cb = { service1: true, service2: true }
侧注
不检查状态中的属性,可以简化_chkbox_check
函数:
_chkbox_check = param => {
this.setState({
cb: {
...this.state.cb,
[param]: !this.state.cb[param],
},
});
}
这是因为JS使用truthy values,所以undefined
将被解释为false。