[React Native] 컴포넌트 이해 - functional componenet 외부에서 state 호출할 수 없는 경우

Nadan
Nadan Dev Blog

개요

블로그 혹은 커뮤니티 앱을 만들 때, 디테일 화면에서 ‘편집’ 버튼이 헤더에 들어가는 경우가 있다. 이 경우 헤더 아이콘의 onPress 함수에서 state 값을 변경해 줘야 하는데 만약 react native에서 제공해주는 default 헤더를 사용하고 있다면 navigationOptions에 onPress 설정해 줘야 한다.

문제는 이렇게 할 경우 navigationOptions에서 state를 호출할 수 없다는 오류가 생긴다. 정확하게는 component function 밖에서는 hook을 호출할 수 없다는 오류이다. 가장 쉬운 해결 방법은 custom 헤더를 만드는 것인데, 헤더에 복잡한 기능이 들어가는 것이 아니기 때문에 직접 그리는 것이 가장 좋은 선택일 것이다. 만약 꼭 default 헤더를 사용해야 한다면 navigationOptions의 argument를 통해 전달되는 navigation을 통해 param을 전달할 수 있다.

오류 상황

ShowScreen.navigationOptions = () => {

  const { state, setEditable } = useContext(BlogContext);
  const { editable } = state;
  const [editable, setEditable] = useState(false);

  return {
    headerRight: () => (
      <TouchableOpacity onPress={() => setEditable(!editable)}>
        <Feather name="edit-2" size={24} color="black" />
      </TouchableOpacity>
    ),
    headerRightContainerStyle: {
      paddingHorizontal: 10,
    },
    title: "Show",
    headerBackTitle: "",
  };
};

navigation을 통해 param 전달

param로 object를 전달할 수 있기 때문에 state 값과 이를 변경할 수 있는 함수를 넘겨준다.

const ShowScreen = ({ navigation }) => {
	...
  useEffect(() => {
    const setEditableWrapper = () => {
      setEditable(!editable);
    }
    navigation.setParams({ setEditableWrapper, editable });
  }, [editable]);
	...
};

ShowScreen.navigationOptions = ({ navigation }) => {
  const setEditable = navigation.getParam('setEditableWrapper');
  const editable = navigation.getParam('editable');
  return {
    headerRight: () => (
      <TouchableOpacity 
        onPress={() => setEditable()}
        activeOpacity={1}>
        { !editable ? <Feather name="edit-2" size={24} color="black" /> : null }
      </TouchableOpacity>
    ),
    headerRightContainerStyle: {
      paddingHorizontal: 10
    },
    title: 'Show',
    headerBackTitle: ''
  };
};