kd12345
kd12345

Reputation: 793

React Native custom passcode screen

I am trying to create my own custom passcode screen but unfortunately its not working. When i try to press on any of the buttons (numbers and back button) they do not work.

I have tried logging in the console the password variable to see if the numbers are getting logged when they are pressed but for some reason all the numbers get logged except the 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}

Upvotes: 0

Views: 613

Answers (1)

Lakshman Kambam
Lakshman Kambam

Reputation: 1618

mistake that you made was you're mutating state array in your onPress methods

let tempCode = password;

instead use Spread Operator to Shallow copy

let tempCode = [...password];

enter image description here

Remember: do not assign duplicate keys to View when you map multiple dataSets because it doesn't know which view to update when changes occurred.

<View key={shouldBeUnique} />

Ever since ES6 dropped, this has been the most popular method. It’s a brief syntax and you’ll find it incredibly useful when using libraries like React and Redux etc.,

Note: This doesn’t safely copy multi-dimensional arrays. Array/object values are copied by reference instead of by value.

i made lot of changes and created working example in expo snack for you. check it.

Expo Snack: 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
  }
});

Upvotes: 1

Related Questions