본문 바로가기

React Native

[React Native] HOC (High Order Component)

728x90

hoc는 리액트에서 제공하는 기능이 아닌 리액트 프로젝트를 구성하는데 쓰이는 패턴으로, 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수로 사용됩니다.

 

hoc가 사용되는 대표적인 예로는 권한 검사, 로그인 상태 검사 등이 있습니다.

다음은 특정 컴포넌트에 접근권한 및 로그인 상태를 검사하기 위해 hoc를 사용하는 예시 입니다.

const Auth = (SpecificComponent, loginRequired, adminRequired = null) => {}

 

우선 권한 및 로그인 상태를 검사하는 hoc인 Auth함수는 컴포넌트, 로그인 필요 여부, 관리자 권한 필요 여부를 인자로 갖습니다.

 

각각의 인자는 다음과 같은 역할을 하게 됩니다.

  • SpecificComponent : hoc를 수행한 후, 렌더링 할 컴포넌트,
  • loginRequired: 해당 컴포넌트가 로그인이 필요한 컴포넌트인지 아닌지를 검사하는 필드,
    • null = 로그인 여부와 상관없이 모두 허용 (ex : 메인 홈페이지),
    • true = 로그인 한 사용자만 허용,
    • false = 로그인 하지 않은 사용자만 허용 (ex : 로그인 페이지)
  • adminRquired: 해당 컴포넌트가 관리자 권한이 필요한 컴포넌트인지 아닌지를 검사하는 필드,
    • false = 기본값, 관리자 권한 상관없이 모두 허용,
    • true = 관리자 권한을 가진 사용자만 허용,

 

다음은 권한 및 로그인 상태를 검사하는 hoc의 내부 코드입니다.

const Auth = (SpecificComponent, loginRequired, adminRequired = false) => {
	const AuthenticationCheck = (props) => {
    	useEffect(() => {
            //로그인한 유저가 없는 경우
            if (!props.user) {
            	//해당 컴포넌트가 로그인이 필요한경우
                if (loginRequired) {
                	props.navigation.replace('Login');
                } else {
                	//로그인이 필요하지 않은 컴포넌트의 경우 특별한 동작 수행이 필요하지 않음
                }
            } else {	//로그인한 유저가 있는 경우
            	//해당 컴포넌트가 로그인 하지 않은 유저만 허용하는 경우(ex : 로그인 페이지)
            	if (loginRequired === false) {
                	props.navigation.replace('Main');
                }
                //해당 컴포넌트가 관리자 권한이 필요한 경우
                if (adminRequired) {
                    if (Role.isAdmin(props.user)) {
                    	//관리자 권한이 필요하고, 사용자가 관리자 권한이 있는 경우 별다른 동작 수행이 필요하지 않음
                    } else {
                    	props.navigation.replace('Main');
                    }
                }
            }
        }, []);
        
        return <SpecificComponent {...props} />;
	};
    return AuthenticationCheck;
}

export default inject(Auth)

 

위에서 구현한 hoc를 사용하는 코드입니다.

export default function AppNavigator() {
  return (
    <NavigationContainer>
      <Provider store={{user: user}}>
        <Stack.Navigator
          screenOptions={() => ({
            headerShown: false,
            ...TransitionPresets.SlideFromRightIOS,
          })}>
          <Stack.Screen name="Main" component={Auth(MainScreen, null)} />
          <Stack.Screen name="Login" component={Auth(LoginScreen, false)} />
          <Stack.Screen name="Setting" component={Auth(SettingScreen, true, true)} />
        </Stack.Navigator>
      </Provider>
    </NavigationContainer>
  );
}
728x90