Chat App (3) :  Auth 화면 구성

Sang heon lee·2022년 6월 23일
0

1. 로그인 화면 - Input 컴포넌트

1.1 forwardRef 사용

  • ref 를 props처럼 전달받아 사용
  • Typescript 에러를 해결 못함.

1.2 다양한 CSS 속성 표시

  • secureTextEntry : 비밀번호 ** 표시
  • autoCapitalize : 첫글자 대문자 방지
  • autoCorrect : 자동 고침 방지
import React, { useState, forwardRef } from 'react';
import { ReturnKeyTypeOptions, TextInput } from 'react-native';
import styled from 'styled-components/native';
import { themeType } from '../theme';

interface styledPropsType {
  theme: themeType;
  isFocused: boolean;
}

const Container = styled.View`
  flex-direction: column;
  width: 100%;
  margin: 10px 0;
`;

const Label = styled.Text<styledPropsType>`
  color: ${({ theme, isFocused }) =>
    isFocused ? theme.text : theme.inputLabel};
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 6px;
`;

const StyledInput = styled.TextInput.attrs<styledPropsType>(({ theme }) => ({
  placeholderTextColor: theme.inputPlaceholder,
}))<styledPropsType>`
  width: 100%;
  background-color: ${({ theme }) => theme.inputBackground};
  color: ${({ theme }) => theme.text};
  padding: 20px 10px;
  font-size: 16px;
  border: 1px solid
    ${({ theme, isFocused }) => (isFocused ? theme.text : theme.inputBorder)};
  border-radius: 4px;
`;

interface props {
  label?: string;
  value?: string;
  onChangeText?: (text: string) => void;
  onSubmitEditing?: () => void;
  onBlur?: () => {};
  placeholder?: string;
  returnKeyType?: ReturnKeyTypeOptions;
  maxLength?: number;
  textContentType?: string;
  isPassword?: boolean;
}

const Input = forwardRef(
  (
    {
      label,
      value,
      onChangeText,
      onSubmitEditing,
      onBlur,
      placeholder,
      returnKeyType,
      maxLength,
      isPassword,
    }: props,
    ref?: React.Ref<TextInput>,
  ) => {
    const [isFocused, SetIsFocused] = useState(false);

    return (
      <Container>
        <Label isFocused={isFocused}>{label}</Label>
        <StyledInput
          ref={ref}
          value={value}
          onChangeText={onChangeText}
          onSubmitEditing={onSubmitEditing}
          onBlur={() => {
            SetIsFocused(false);
            onBlur;
          }}
          placeholder={placeholder}
          returnKeyType={returnKeyType}
          maxLength={maxLength}
          autoCapitalize="none"  // 첫글자 대문자 방지
          autoCorrect={false}   // 자동 고침 방지
          isFocused={isFocused}
          onFocus={() => SetIsFocused(true)}
          secureTextEntry={isPassword} // 비밀번호 ** 표시용
        />
      </Container>
    );
  },
);

export default Input;

2. 회원 가입 화면

2.1 키보드 입력시 화면 가림 현상 제거

https://github.com/APSL/react-native-keyboard-aware-scroll-view

  • 여유 공간 생성 : extraScrollHeight
  • android 정상동작 : enableOnAndroid
// src/screens/Signup.tsx
import React, { useState, useRef } from 'react';
import styled from 'styled-components/native';
import { themeType } from '../theme';
import { Button, Image, Input } from '../components';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { TextInput } from 'react-native';
// ⭐️⭐️⭐️⭐️
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';

const Conatiner = styled.View<styledPropsType>`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: ${({ theme }) => theme.background};
  padding: 50px 20px;
  /* padding-top: ${({ insets }) => insets.top}px;
  padding-bottom: ${({ insets }) => insets.bottom}px; */
  /* padding-left: ${({ insets }) => insets.left}px;
  padding-right: ${({ insets }) => insets.right}px; */
`;

interface styledPropsType {
  insets: {
    bottom: number;
    left: number;
    right: number;
    top: number;
  };
  theme: themeType;
}

const Signup = () => {
  const insets = useSafeAreaInsets();

  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [passwordConfirm, setPasswordConfirm] = useState('');

  const refEmail = useRef<TextInput | null>(null);
  const refPassword = useRef<TextInput | null>(null);
  const refPasswordConfirm = useRef<TextInput | null>(null);

  const _handleSingupBtnPress = () => {
    console.log('signup');
  };

  return (
    // ⭐️⭐️⭐️⭐️
    <KeyboardAwareScrollView extraScrollHeight={20} enableOnAndroid={true}> 
      <Conatiner insets={insets}>
        <Image />
        <Input
          label="Name"
          value={name}
          placeholder="Name"
          onChangeText={setName}
          returnKeyType="next"
          maxLength={20}
          textContentType="none"
          onSubmitEditing={() => refEmail.current?.focus()}
        />
        <Input
          ref={refEmail}
          label="Email"
          value={email}
          placeholder="Email"
          onChangeText={setEmail}
          returnKeyType="next"
          maxLength={20}
          textContentType="none"
          onSubmitEditing={() => refPassword.current?.focus()}
        />
        <Input
          ref={refPassword}
          label="Password"
          value={password}
          placeholder="Password"
          onChangeText={setPassword}
          returnKeyType="next"
          maxLength={20}
          textContentType="none"
          isPassword={true}
          onSubmitEditing={() => refPasswordConfirm.current?.focus()}
        />
        <Input
          ref={refPasswordConfirm}
          label="Password Confirm"
          value={passwordConfirm}
          placeholder="Password"
          onChangeText={setPasswordConfirm}
          returnKeyType="done"
          maxLength={20}
          textContentType="none"
          isPassword={true}
          onSubmitEditing={_handleSingupBtnPress}
        />
        <Button title="Sign up" onPress={_handleSingupBtnPress} />
      </Conatiner>
    </KeyboardAwareScrollView>
  );
};

export default Signup;
  • 화면 상단으로 쏠림 현상 제거 : contentContainerStyle
// src/screens/Signin

import React, { useContext, useState, useRef } from 'react';
import styled from 'styled-components/native';
import { ThemeContext } from 'styled-components';
import { themeType } from '../theme';
import { Button, Image, Input } from '../components';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StackNavigationProp } from '@react-navigation/stack';
import { AuthStackParamList } from '../navigations/Auth';
import { TextInput } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';

const Conatiner = styled.View<styledPropsType>`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: ${({ theme }) => theme.background};
  padding: 0 20px;
  padding-top: ${({ insets }) => insets.top}px;
  padding-bottom: ${({ insets }) => insets.bottom}px;
  /* padding-left: ${({ insets }) => insets.left}px;
  padding-right: ${({ insets }) => insets.right}px; */
`;

interface styledPropsType {
  insets: {
    bottom: number;
    left: number;
    right: number;
    top: number;
  };
  theme: themeType;
}

type SigninScreenNavPropsType = StackNavigationProp<
  AuthStackParamList,
  'Signin'
>;
type Props = {
  navigation: SigninScreenNavPropsType;
};

const LOGO =
  'https://firebasestorage.googleapis.com/v0/b/react-native-chat-app-d8603.appspot.com/o/logo.png?alt=media';

const Signin = ({ navigation }: Props) => {
  const insets = useSafeAreaInsets();
  const theme = useContext(ThemeContext);

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const refPassword = useRef<TextInput | null>(null);

  const _handleSinginBtnPress = () => {
    console.log('signin');
  };

  return (
    // ⭐️⭐️⭐️⭐️
    <KeyboardAwareScrollView
      extraScrollHeight={20}
      contentContainerStyle={{ flex: 1 }}
    >
      <Conatiner insets={insets}>
        <Image url={LOGO} />
        <Input
          label="Email"
          value={email}
          placeholder="Email"
          onChangeText={setEmail}
          returnKeyType="next"
          maxLength={20}
          textContentType="none"
          onSubmitEditing={() => refPassword.current?.focus()}
        />
        <Input
          ref={refPassword}
          label="Password"
          value={password}
          placeholder="Email"
          onChangeText={setPassword}
          returnKeyType="done"
          maxLength={20}
          isPassword={true}
          onSubmitEditing={_handleSinginBtnPress}
        />
        <Button title="Sign in" onPress={_handleSinginBtnPress} />
        <Button
          title="Sign up with email"
          onPress={() => {
            navigation.navigate('Signup');
          }}
          containerStyle={{ marginTop: 0, backgroundColor: 'transparent' }}
          textStyle={{ color: theme.btnTitleLink, fontSize: 18 }}
        />
      </Conatiner>
    </KeyboardAwareScrollView>
  );
};

export default Signin;
profile
개초보

0개의 댓글