react-native - React Native 自定义密码屏幕
问题描述
我正在尝试创建自己的自定义密码屏幕,但不幸的是它不起作用。当我尝试按下任何按钮(数字和后退按钮)时,它们不起作用。
我已经尝试在控制台中登录密码变量,以查看按下数字时是否记录了数字,但由于某种原因,除了 0 之外,所有数字都被记录了。
const[password,setPassword]=useState(['','','',''])
let numbers =[
{id:1},
{id:2},
{id:3},
{id:4},
{id:5},
{id:6},
{id:7},
{id:8},
{id:9},
{id:0},
]
const onPressNumber =(num)=>{
let tempCode = password;
for(var i=0;i<tempCode.length;i++){
if(tempCode[i]==''){
tempCode[i]=num;
break;
}else{
continue;
}
}
setPassword(tempCode)
}
const onPressBack =(num)=>{
let tempCode = password;
for(var i=tempCode.length-1;i>=0;i--){
if(tempCode[i]!=''){
tempCode[i]='';
break;
}else{
continue;
}
}
setPassword(tempCode)
}
return(
<View>
{
password.map(p=>{
let style =p != ''?
{width:15,
height:15,
borderRadius:15,
backgroundColor:'blue'}
:
{width:15,
height:15,
borderRadius:15,
backgroundColor:'white'}
return <View style={style}></View>
})
}
</View>
<View style={{alignItems:'center',justifyContent:'center'}}>
<View style={styles.numbersContainer}>
{numbers.map(num=>{
return(
<TouchableOpacity
style={styles.number}
key={num.id}
onPress={()=>{onPressNumber(num.id)}}>
<Text style={styles.numberText}>{num.id}</Text>
</TouchableOpacity>
)
})}
</View>
</View>
{password != ''?
<View style={styles.button}>
<TouchableOpacity onPress={()=>onPressBack()}>
<Ionicons name="arrow-back" size={30} color="black" />
</TouchableOpacity>
</View>
:null}
解决方案
你犯的错误是你在 onPress 方法中改变状态数组
let tempCode = password;
而是使用扩展运算符来浅拷贝
let tempCode = [...password];
请记住:在映射多个数据集时不要分配重复的键,View
因为它不知道发生更改时要更新哪个视图。
<View key={shouldBeUnique} />
自从 ES6 下降以来,这一直是最流行的方法。这是一个简短的语法,你会发现它在使用 React 和 Redux 等库时非常有用,
注意:这不能安全地复制多维数组。数组/对象值是按引用而不是按值复制的。
我做了很多改变,并为你在世博小吃中创建了工作示例。核实。
世博小吃:https ://snack.expo.io/@klakshman318/belligerent-celery
import React, {useState, useEffect} from 'react';
import { Text, View, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
// to generate serial number based on count as argument
const getSerialNumbers = (count) => {
const numbersArray = [];
for(let i = 0; i < count; i++) {
numbersArray.push({
number:i.toString(),
empty: false
});
}
// to make even - which are not full rows will be added empty object with empty key set to true
const fullRows = Math.floor(numbersArray.length/2);
let lastRow = numbersArray.length-(fullRows*2);
while (lastRow!==2 && lastRow!==0) {
numbersArray.push({ _id: `blank-${lastRow}`, empty: true });
lastRow++;
}
return numbersArray;
}
export default function App() {
const [passwords, setPassword] = useState(['','','','']);
useEffect(() => {
// alert(JSON.stringify(passwords));
}, [passwords]);
const onPressNumber = (num) => {
let tempPassCode = [...passwords];
for(var i=0;i<tempPassCode.length;i++){
if(tempPassCode[i]==''){
tempPassCode[i]=num;
break;
}else{
continue;
}
}
setPassword(tempPassCode)
}
const onPressBack =(num)=>{
let tempPassCode = [...passwords];
for(let i=tempPassCode.length-1;i>=0;i--){
if(tempPassCode[i]!=''){
tempPassCode[i]='';
break;
}else{
continue;
}
}
setPassword(tempPassCode);
}
// Number Pad FlatList render each Item
const renderNumPadBtnItem = ({item}) => {
if(item.empty) {
return (
<TouchableOpacity onPress={() => onPressBack()} style={{flex:1, alignItems:'center', marginHorizontal:3, backgroundColor:'#B0D7FF', padding:12}}>
<Text style={{color:'black', fontSize:18}}>Go Back</Text>
</TouchableOpacity>
);
}
return (
<TouchableOpacity
onPress={()=> onPressNumber(item.number)}
style={{flex:1, alignItems:'center', marginHorizontal:3, backgroundColor:'#ccc', padding:12}}
>
<Text style={{color:'black', fontSize:18}}>{item.number}</Text>
</TouchableOpacity>
);
}
// NumberPad FlatList
const renderNumberKeyPad = () => {
const numkeyPadData = getSerialNumbers(11);
return (
<FlatList
numColumns={3}
ItemSeparatorComponent={() => (
<View style={{padding:3}} />
)}
data={numkeyPadData}
renderItem={renderNumPadBtnItem}
keyExtractor={item => item.number}
/>
);
}
const renderPassCodeData = () => {
}
return (
<View style={styles.containerWrap}>
<View style={styles.passCodeContainer}>
{passwords.map(pItem => {
return (
<View
key={pItem+Math.random()}
style={[styles.passCodeBox, {
backgroundColor: pItem != '' ? '#96DED1' : 'white'
}]}
>
<Text style={{color:pItem ? 'white' : 'black', fontSize:16, opacity: pItem ? 1 : 0.2}}>
{pItem ? pItem : '0'}
</Text>
</View>
)
})}
</View>
<View style={styles.spacingM12}>
{renderNumberKeyPad()}
</View>
</View>
)
}
const styles = StyleSheet.create({
containerWrap: {
flex: 1,
},
passCodeContainer: {
backgroundColor:'#00A36C',
paddingVertical:12,
flexDirection:'row'
},
passCodeBox: {
padding:12,
alignItems:'center',
marginHorizontal:6,
flex:1,
},
spacingM12: {
marginTop:12
}
});
推荐阅读
- python - 当列名相同时重命名DataFrame中的列
- sql - 是否可以在 Azure 和 SQL 中使用跨数据库查询?
- python - 锁定多线程 pywinauto 发送密钥
- jquery - 如果您只做一个小的滚动轻推或冲动,则滚动到元素
- c# - VS 2017 .Net core 2.2 中缺少 Blazor 模板
- c++ - 创建对象的第二个实例会改变整个类的行为 (C++)
- tomcat - 我的 Tomcat RewriteRules 没有被正确读取
- networking - 用户的 IP 地址可以在浏览会话中使用吗?
- r - 与 R 中的“ifelse”相比,创建新变量的更好方法是什么?
- java - 有没有办法检查某些生成的代码在不使用 implements 关键字时是否遵守接口?