이런저런 IT 이야기
ReactNative 화면 전환시 데이터 주고 받기 본문
ReactNative 개발하면서 가장 신경이 쓰이는 것이 화면간 데이터를 주고 받는 부분입니다.
이 부분에 좀더 효과적으로 대응하기 위해서 Context 개념을 적용하여 모든 화면에서 데이터가 공유될수 있도록 구현해보았습니다.
샘플코드는 아래 링크를 참조하세요.
https://github.com/leeyonghe/ReactNativeApp
Context는 React or React Native 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법입니다.
Context를 사용하면 모든 컴포넌트를 일일이 통하지 않고도// 원하는 값을 컴포넌트 트리 깊숙한 곳까지 보낼 수 있습니다.
정말 편하죠.
코드설명을 하겠습니다. 총 5개 파일만 익히시면 됩니다.
./Core/CoreManagement.js
import React, {Component, createContext} from 'react';
const CC = createContext({
value: 0,
tag: '',
SetValue: () => {},
});
export const CoreContext = CC;
export const CoreConsumer = CC.Consumer;
export class CoreProvider extends Component {
SetValue = (value) => {
this.state.value = value;
};
state = {
value: 0,
tag: '>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
SetValue: this.SetValue
};
render() {
return <CC.Provider value={this.state}>{this.props.children}</CC.Provider>;
}
}
createContext 라는 함수로 CoreContext를 만들고, 이 함수를 호출하고 Consumer 라는 컴포넌트가 반환됩니다.
CoreProvider는 별도로 Class를 선언하여 부모 Layer에서 사용하고 CoreConsumer 는
그 하위 Layer 에서 사용합니다.
제가 여기서 시연하고 싶은 부분은 value값을 화면 2개가 왔다갔다 하면서 값을 공유하면서 +1을 하는 겁니다.
그렇게 하기 위해서 CoreProvider에서 변수, 함수를 공유하고 있다는 겁니다.
변수 : value
변수 : tag
함수 : SetValue: () => {}
App.js
import React from 'react';
import {CoreProvider} from './Core/CoreManagement';
import Route from './Route';
const App: () => React$Node = () => {
return (
<>
<CoreProvider>
<Route />
</CoreProvider>
</>
);
};
export default App;
App.js는 기본이죠. 최초 앱이 시작되는 Entry Point입니다. 특히 CoreContext를 잘 보세요.
하위 Layer에 Route보이시죠. 즉 뷰(또는 뷰들)을 저 CoreProvider가 감싸야 합니다.
그래야 하위 Layer들이 값을 서로 공유가 가능해요.
Route.js
import React, {useContext} from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {CoreContext} from './Core/CoreManagement';
const Stack = createStackNavigator();
import View1 from './View1';
import View2 from './View2';
export default function Route(props) {
const result = useContext(CoreContext);
console.log(result.tag + ' Route ');
console.log(result.tag + ' Route result : ' + JSON.stringify(result));
return (
<NavigationContainer>
<Stack.Navigator headerMode={'none'} initialRouteName="View1">
<Stack.Screen name="View1" component={View1} />
<Stack.Screen name="View2" component={View2} />
</Stack.Navigator>
</NavigationContainer>
);
}
저는 Stack Navigation를 이용하여 하위 View들이 CoreProvider가 선언한 값, 함수를 공유합니다.
여기는 특별한건 없습니다.
View1.js
/* eslint-disable react-native/no-inline-styles */
import React, {useEffect, useContext, useState} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Image,
ActivityIndicator,
Button
} from 'react-native';
import {CoreContext, CoreConsumer} from './Core/CoreManagement';
import {useNavigation} from '@react-navigation/native';
export default function View1(props) {
const navigation = useNavigation();
const {route} = props;
const {params} = route;
const result = useContext(CoreContext);
console.log(result.tag + ' View1 ');
console.log(result.tag + ' View1 ' + result.value);
const [backValue , SetbackValue] = useState(result.value);
useEffect(() => {
const focus = props.navigation.addListener('focus', async () => {
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>> View1 Refresh');
console.log(
'>>>>>>>>>>>>>>>>>>>>>>>>>>>> props ' + JSON.stringify(props),
);
SetbackValue(result.value);
});
return focus;
}, [props, props.navigation]);
return (
<CoreConsumer>
{({value, SetValue}) => (
<View
style={{
alignItems: 'center',
justifyContent: 'center',
flex: 1,
backgroundColor: '#828192',
}}>
<Text>View1 : {backValue} </Text>
<Button
title="Next"
onPress={() => {
SetValue(backValue + 1);
navigation.navigate('View2');
}}
/>
</View>
)}
</CoreConsumer>
);
}
View2.js
import React, {useEffect, useContext} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Image,
ActivityIndicator,
Button
} from 'react-native';
import {CoreContext, CoreConsumer} from './Core/CoreManagement';
import {useNavigation} from '@react-navigation/native';
export default function View2(props) {
const navigation = useNavigation();
const {route} = props;
const {params} = route;
const result = useContext(CoreContext);
console.log(result.tag + ' View2 ');
useEffect(() => {
const focus = props.navigation.addListener('focus', async () => {
// console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>> View2 Refresh');
console.log(
'>>>>>>>>>>>>>>>>>>>>>>>>>>>> props ' + JSON.stringify(props),
);
});
return focus;
}, [props, props.navigation]);
return (
<CoreConsumer>
{({value, SetValue}) => (
// eslint-disable-next-line react-native/no-inline-styles
<View
// eslint-disable-next-line react-native/no-inline-styles
style={{
alignItems: 'center',
justifyContent: 'center',
flex: 1,
backgroundColor: '#273623',
}}>
<Text>View2 : {value} </Text>
<Button
title="Next"
onPress={() => {
SetValue(result.value + 1);
navigation.goBack();
}}
/>
</View>
)}
</CoreConsumer>
);
}
여기에 CoreConsumer가 나옵니다. 상위 뷰에서 선언한 CoreProvider와 공유된 변수 및 함수를 하위 뷰들과 공유하는 겁니다.
특히 주의 깊게 보셔야 할 부분은 다름아닌 랜더링 진입 전 및 후 입니다.
랜더링 진입전 :
개발자들은 뷰 함수에 진입시 미리 값을 불러와 최초 화면을 그리기전에 하고 싶은 작업이 있습니다. 대표적인게 서버통신일 겁니다.
const result = useContext(CoreContext);
const [backValue , SetbackValue] = useState(result.value);
위와 같이 useContext를 사용하여 CoreProvider에서 선언한 CoreContext를 불러오면 데이터를 공유 할 수 있습니다.
랜더링 진입후 :
만약 CoreProvider에서 가지고 있는 데이터를 바로 화면에 그리고 싶을때가 있을 겁니다.
{({value, SetValue}) => (
<View
style={{
alignItems: 'center',
justifyContent: 'center',
flex: 1,
backgroundColor: '#828192',
}}>
<Text>View1 : {backValue} </Text>
<Button
title="Next"
onPress={() => {
SetValue(backValue + 1);
navigation.navigate('View2');
}}
/>
</View>
)}
위와 같이 CoreProvider에서 선언한 value, SetValue를 화면에 바로 매핑하여 사용 할 수 있습니다.
Next버튼을 계속 누르면 +1 증가 하게 되고 가장 중요한 포인트는 navigation.goBack(); 입니다.
처음 화면(View1.js)과 두번째 화면(View2.js)은 서로 데이터를 공유하며 앞으로 뒤로 왔다갔다는 액션에서 데이터를
공유하기 때문입니다.
데이터 가져오는 부분으로 고생하시는 분들께 도움이 되었으면 합니다.
궁금하신 부분은 댓글남겨주세요.
'React Native' 카테고리의 다른 글
MacOS Big Sur 업데이트후 RN Android 빌드 에러 (MacOS) (1) | 2020.11.16 |
---|---|
React-Native iOS : main.jsbundle 이슈 (0) | 2020.10.28 |
React Native Apple 로그인 연동 (0) | 2020.08.07 |