ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • <TIL> redux 적용 로그인 인증 화면 만들기 - Trello(7)
    TIL 2020. 4. 13. 16:24

    한동안 바빠 1일1커밋 지키지 못하였다...

     

    로그인 인증 하는 부분에서 return 안에 인증하는 함수를 실행시켰더니 함수가 계속 작동되는 비효율적인 인증 방법이 실행이 되었습니다.
    이러한 부분을 Redux 적용하여 훨씬 간단하게 인증할 수 있게 구현 하였습니다.

     

    1. Reducer, action 함수 만들기

     

    일단 그러면 redux에 action의 타입과 action 함수를 만들어 줍니다.

     

    redux를 사용할 component에서 action함수를 꺼내 사용해야 하기 때문에 export를 앞에 넣어 줘야 합니다.

    export const SaveToken = 'SAVETOKEN';
    // 액션 타입 정의
    
    export const saveTokenInStore = () => ({ type: SaveToken });

     

    그러한 다음 state기본 값은 initalTokenStore으로 지정해 주고 state의 값을 변경해주는 Reducer을 만들어 줍니다.

     

    Reducer의 역할은 action함수가 실행이 되면 action의 type에 맞는 state로 값을 변경해주는 일을 합니다.

    const initalTokenStore = {
      SavetokenInStorage: false,
    };
    
    export default function State(state = initalTokenStore, action) {
      switch (action.type) {
        case SaveToken:
          return {
            SavetokenInStorage: true,
          };
        default:
          return state;
      }
    }

     

    2.Store 만들기

    Provider를 이용한 component에서 connect를 사용할 수 없기 때문에 App.js에서 라우터를 관리하던 것을 두개의 component로 쪼개 버렸습니다.

     

    App.js에서는 provider를 이용하여 Store를 적용하는 일만 하고

    import { createStore } from 'redux';
    import React, { Component } from 'react';
    import { Provider } from 'react-redux';
    import Nav from './Nav';
    import Reducer from './components/Redux/Reducer';
    
    const store = createStore(Reducer);
    
    
    class App extends Component {
      render() {
        return (
            <Provider store={store}>
              <Nav />
            </Provider>
        );
      }
    }
    
    export default App;

    Nav.js에서는 navigation이용하여 라우터를 구현 하고 connect를 적용하여 component에 login이 되었는지 체크 didmount로 AsyncStorage에 값의 유무를 확인하여 자동 로그인을 할 수 있게 만들었습니다

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import 'react-native-gesture-handler';
    import { AsyncStorage } from 'react-native';
    import { NavigationContainer } from '@react-navigation/native';
    import { createStackNavigator } from '@react-navigation/stack';
    import { createDrawerNavigator } from '@react-navigation/drawer';
    import { SafeAreaProvider } from 'react-native-safe-area-context';
    import { saveTokenInStore } from './Redux/Reducer';
    components ...;
    
    const Stack = createStackNavigator();
    const Drawer = createDrawerNavigator();
    
    function StackBoard() {
      return (
          <Stack.Navigator>
            <Stack.Screen name="Boards" component={Board} options={{ title: 'Boards' }} />
            <Stack.Screen name="InBoard" component={InBord} />
            <Stack.Screen name="MakeBoard" component={MakeBoard} options={{ title: 'MakeBoard' }} />
            <Stack.Screen name="MakeCard" component={MakeCard} options={{ title: 'MakeCard' }} />
            <Stack.Screen name="MakeContainer" component={MakeContainer} options={{ title: 'MakeContainer' }} />
            <Stack.Screen name="Containers" component={Containers} />
          </Stack.Navigator>
      );
    }
    
    class Nav extends Component {
      constructor() {
        super();
        this.state = {
          Login: false,
        };
      }
    
      async componentDidMount() {
        if (await AsyncStorage.getItem('user_Token')) {
          this.props.loginCheck();
        }
      }
    
      render() {
        return (
          <NavigationContainer>
          <SafeAreaProvider>
            { this.props.Login ? (
                <Drawer.Navigator>
                    <Drawer.Screen name="Home" component={Home} options={{ title: 'Home' }} />
                    <Drawer.Screen name="Boards" component={StackBoard} />
                    <Drawer.Screen name="UserInfo" component={UserPage} />
                </Drawer.Navigator>
            ) : (
              <Stack.Navigator screenOptions={{
                headerShown: false,
              }}>
                <>
                  <Stack.Screen name="First Screen" component={First} />
                  <Stack.Screen name="Signup Screen" component={Signup} />
                  <Stack.Screen name="Login Screen" component={Login} />
                </>
              </Stack.Navigator>
            )}
          </SafeAreaProvider>
          </NavigationContainer>
        );
      }
    }
    
    const mapStateToProps = ({ SavetokenInStorage }) => ({
      Login: SavetokenInStorage,
    });
    
    const mapDispatchToProps = (dispatch) => ({
      loginCheck: () => {
        dispatch(saveTokenInStore());
      },
    });
    
    export default connect(mapStateToProps, mapDispatchToProps)(Nav);

     

    3. login 화면에 적용

    import React, { Component } from 'react';
    ...
    import { saveTokenInStore } from '../Redux/Reducer';
    
    class Login extends Component {
      constructor(props) {
        super(props);
        this.state = {
          password: null,
          email: null,
          loginFailAlert: false,
          successAlert: false,
        };
        this.serverConnect = this.serverConnect.bind(this);
      }
    
    
      serverConnect() {
        const { email, password } = this.state;
        if (this.state.email === null || this.state.password === null) {
          this.setState({
            loginFailAlert: true,
          });
        } else {
          axios.post(`${server}/user/login`, { email, password })
            .then(async (res) => {
              if (res.status === 201) {
                await AsyncStorage.setItem('user_Token', res.data.token);
                this.props.loginCheck();
              } else {
                this.setState({
                  errAlert: false,
                });
              }
            });
        }
      }
    
      render() {
        return (
            <View style={styles.total}>
            <View style={styles.AppName}>
                <Text style={{ fontSize: 50 }}>
                Hi!
                </Text>
            </View>
            <View style={styles.Inputs}>
            <Isao
                    label="Email"
                    style={{ width: 330, marginTop: 15 }}
                    activeColor="#da7071"
                    borderHeight={8}
                    inputPadding={16}
                    labelHeight={24}
                    passiveColor="black"
                    onChangeText={(text) => this.setState({ email: text })}
              />
                <Isao
                    label="Password"
                    style={{ width: 330, marginBottom: 10 }}
                    activeColor="#da7071"
                    borderHeight={8}
                    inputPadding={16}
                    labelHeight={24}
                    passiveColor="black"
                    onChangeText={(text) => this.setState({ password: text })}
              />
                <View style={{ flexDirection: 'row' }}>
                <Button
                title="로그인"
                type="outline"
                buttonStyle={{ width: 90, height: 40 }}
                onPress={this.serverConnect} />
                <TouchableOpacity onPress={() => this.props.navigation.navigate('Signup Screen')}>
                    <Text>
                        회원가입
                    </Text>
                </TouchableOpacity>
                </View>
                <Alert
            show={this.state.loginFailAlert}
            title="로그인 실패"
            message="로그인에 실패하였습니다."
            confirmText="로그인 다시 하기"
            onConfirmPressed={() => this.setState({
              loginFailAlert: false, email: null, password: null,
            })} />
            </View>
            </View>
        );
      }
    }
    const styles = StyleSheet.create({
      ...
    });
    
    const mapDispatchToProps = (dispatch) => ({
      loginCheck: () => {
        dispatch(saveTokenInStore());
      },
    });
    
    export default connect(null, mapDispatchToProps)(Login);

    'react-redux' 의 connect를 이용하여 컴포넌트에 props에 loginCheck라는 함수로 action함수를 넘겨 줍니다.

     

    로그인이 성공하면 AsyncStorage에 토큰 값이 저장이 되고 action함수가 실행이 되면서 store의 값도 saveTokenInStorage의 값도 true로 변경이 됩니다.

    댓글

Designed by Tistory.