[React Native] 화면 전환(focus) 이벤트

Nadan
Nadan Dev Blog

화면 전환(focus) 이벤트

다른 화면으로 전환되거나, 현재 화면으로 들어올 때 화면 focus 변화를 탐지하기 위해 사용함. 예를 들어, 어떻게 화면으로 돌아올 때 데이터가 갱신되게 할 수 있을까? 이럴 때 사용함

AppState랑은 활용이 확실이 다른데 처음에 좀 헷갈림. AppState는 앱을 종료하거나, 전화가 오는 등 다른 앱으로 잠시 전환되는 상황에 앱 상태를 탐지하기 위해 사용하는 것임

navigation listener, NavigationEvent는 생각보다 작동이 잘 안 됨. withNavigationFocus이 예의 거의 없이 제일 작동 잘 하는 듯.

1) Navigation Listener

navigation에 리스너를 단 후 리스너 제거할 때 return 값이 listener.remove()가 아니라 () ⇒ listener.remove()임

useEffect(() => {
    getBlogPosts();

    // any time return to the screen
    const listener = navigation.addListener('didFocus', () => {
        getBlogPosts();
    });
  
    // const listener = navigation.addListener('willBlur', () => {
    // });

    // memory leak 방지하기 위해 컴포넌트를 사용핮 않을 때 제거
    // 컴포넌트 사용이 중지될 떄 호출됨
    return () => {
        listener.remove();
    }
}, []);

2) NavigationEvents

이것과 별개로, 에러 메시지가 뜨면 회원가입 페이지에서도 에러 메시지가 뜸. state가 공용이고, 화면이 사라진 게 아니라 안 보이게 된 것이기 때문. 블로그 만들 때도 비슷한 일이 있었는데, 뒷 페이지로 갈 때 새로 데이터를 갱신하게 하는 것이었음. 이 때 활용한 것이 이벤트 리스너

  • onWillFocus → 해당 페이지가 호출 됬을 때
  • onDidFocus → 해당 페이지가 화면이 띄워졌을 때
  • onWillBlur → 화면에서 나가는 버튼이 눌렸을 때
  • onDidBlur → 화면에서 사라졌을 떄

유의점

onWillBlur가 안 되는 경우가 있음. onWillFocus 사용하면 됨

예시)

AuthContext.js

const clearErrorMessage = dispatch => () => {
    dispatch({ type: 'clear_error_message' })
};

export const { Provider, Context } = createDataContext(
    authReducer,
    { signin, signup, signout, clearErrorMessage },
    { token: null, errorMessage: '' }
)

SignInScreen.js

import { NavigationEvents } from 'react-navigation'; 

const SignInScreen = () => {

    const { state, signin, clearErrorMessage } = useContext(AuthContext);
    
    console.log(state.errorMessage);

    return (
        <View style={styles.container}>
            <NavigationEvents 
                onWillFocus={() => clearErrorMessage()}
                // onDidFocus={() => {}}
                // onWillBlur={() => {}}
                // onDidBlur={() => {}}
            />
	          ...
        </View>
    );
};

SignUpScreen.js

import { NavigationEvents } from 'react-navigation'; 

const SignUpScreen = ({ navigation }) => {

    const { state, signup, clearErrorMessage } = useContext(AuthContext);
    
    return (
        <View style={styles.container}>
            <NavigationEvents 
                onWillFocus={() => clearErrorMessage()}
            />
            ...
        </View>
    );
}

3) withNavigationFocus

import { SafeAreaView, withNavigationFocus } from 'react-navigation';
...

const TrackCreateScreen = ({ isFocused }) => {

    const { addLocation } = useContext(LocationContext);

    const [err] = useLocation(isFocused, (location) => addLocation(location))
    
    return (
        <SafeAreaView>
            <Text h2>TrackCreateScreen</Text>
            <Map />
            {err ? <Text>Please enable loaction services</Text> : null}
        </SafeAreaView>
    );
};

export default withNavigationFocus(TrackCreateScreen)

참고) BackHandler Listener

BackHandler.addEventListener('hardwareBackPress',() => {   
    return true;
});