리액트 네이티브에서 컴포넌트와 훅의 개념은 앱의 구조와 상태 관리를 효과적으로 다루기 위해 필수적이다. 여기서는 리액트 네이티브의 컴포넌트와 훅을 깊이 있게 다루며, 각 훅의 기능과 사용법을 상세히 설명하겠다. 또한, 다양한 훅을 실용적인 예제와 함께 설명하겠다.
리액트 네이티브의 컴포넌트는 UI를 구성하는 기본 단위이다. 컴포넌트는 함수형 컴포넌트와 클래스형 컴포넌트로 나눌 수 있다.
함수형 컴포넌트는 간단한 자바스크립트 함수로 정의되며, 주로 렌더링 로직을 처리한다. 함수형 컴포넌트는 훅을 사용하여 상태를 관리하고, 사이드 이펙트를 처리할 수 있다.
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
// 함수형 컴포넌트 정의
const Greeting = ({ name }) => {
return (
<View style={styles.container}>
<Text style={styles.text}>Hello, {name}!</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정한다
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정한다
color: 'blue', // 텍스트 색상을 파란색으로 설정한다
},
});
export default Greeting;
클래스형 컴포넌트는 자바스크립트 클래스를 사용하여 정의되며, 상태와 생명주기 메서드를 가질 수 있다. 복잡한 상태 로직과 생명주기 관리가 필요한 경우에 적합하다.
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
// 클래스형 컴포넌트 정의
class Greeting extends Component {
render() {
const { name } = this.props;
return (
<View style={styles.container}>
<Text style={styles.text}>Hello, {name}!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정한다
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정한다
color: 'blue', // 텍스트 색상을 파란색으로 설정한다
},
});
export default Greeting;
리액트 훅은 함수형 컴포넌트에서 상태와 생명주기 기능을 추가할 수 있게 해주는 함수들이다. 여러 훅이 있으며, 각 훅은 특정한 목적을 가진다. 주요 훅과 그 사용법에 대해 자세히 설명하겠다.
useState
useState
훅은 함수형 컴포넌트에서 상태를 추가할 수 있게 해준다. 이 훅은 현재 상태와 상태를 업데이트할 수 있는 함수를 반환한다.
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// useState 훅을 사용하는 함수형 컴포넌트
const Counter = () => {
const [count, setCount] = useState(0); // 상태 변수와 업데이트 함수 선언
return (
<View style={styles.container}>
<Text style={styles.text}>Count: {count}</Text>
<Button
title="Increment"
onPress={() => setCount(count + 1)} // 버튼 클릭 시 상태 업데이트
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default Counter;
useEffect
useEffect
훅은 부수 효과(side effects)를 처리하는 데 사용된다. 컴포넌트가 렌더링될 때 특정 작업을 수행하거나 컴포넌트가 언마운트될 때 정리 작업을 수행할 수 있다.
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
// useEffect 훅을 사용하는 함수형 컴포넌트
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1); // 매초 상태 업데이트
}, 1000);
return () => clearInterval(intervalId); // 언마운트 시 인터벌 정리
}, []); // 빈 배열을 전달하면 컴포넌트가 마운트될 때만 실행
return (
<View style={styles.container}>
<Text style={styles.text}>Time: {seconds}s</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default Timer;
useContext
useContext
훅은 React의 Context API를 사용하여 전역 상태를 함수형 컴포넌트에서 쉽게 접근할 수 있게 해준다. Context를 생성하고, 제공하고, 소비하는 과정을 간단히 할 수 있다.
import React, { createContext, useContext, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// Context 생성
const ThemeContext = createContext();
// 컨텍스트 공급자 컴포넌트
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value=>
{children}
</ThemeContext.Provider>
);
};
// 컨텍스트를 사용하는 컴포넌트
const ThemedComponent = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<View style={[styles.container, { backgroundColor: theme === 'light' ? 'white' : 'black' }]}>
<Text style=>Current Theme: {theme}</Text>
<Button title="Toggle Theme" onPress={toggleTheme} />
</View>
);
};
const App = () => {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
});
export default App;
useReducer
useReducer
훅은 상태 로직이 복잡할 때 유용하다. 상태와 상태를 업데이트하는 리듀서를 관리하는 함수의 조합으로 상태를 업데이트할 수 있다.
import React, { useReducer } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// 리듀서 함수 정의
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
// useReducer
훅을 사용하는 함수형 컴포넌트
const Counter = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<View style={styles.container}>
<Text style={styles.text}>Count: {state.count}</Text>
<Button title="Increment" onPress={() => dispatch({ type: 'INCREMENT' })} />
<Button title="Decrement" onPress={() => dispatch({ type: 'DECREMENT' })} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default Counter;
useCallback
useCallback
훅은 콜백 함수를 메모이제이션하여 성능을 최적화하는 데 사용된다. 특정 값이 변경되지 않는 한 동일한 콜백 함수를 재사용할 수 있다.
import React, { useCallback, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// ExpensiveComponent 컴포넌트 정의
const ExpensiveComponent = React.memo(({ onClick }) => {
console.log('ExpensiveComponent re-rendered');
return <Button title="Click me" onPress={onClick} />;
});
const App = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<View style={styles.container}>
<Text style={styles.text}>Count: {count}</Text>
<ExpensiveComponent onClick={handleClick} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default App;
useMemo
useMemo
훅은 계산 비용이 높은 값의 메모이제이션을 제공하여 성능 최적화를 돕는다. 특정 값이 변경되지 않는 한 동일한 계산 결과를 재사용한다.
import React, { useMemo, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// ExpensiveComponent 컴포넌트 정의
const ExpensiveComponent = ({ value }) => {
const computedValue = useMemo(() => {
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
return sum;
}, [value]);
return <Text style={styles.text}>{`Computed Value: ${computedValue}`}</Text>;
};
const App = () => {
const [value, setValue] = useState(0);
return (
<View style={styles.container}>
<ExpensiveComponent value={value} />
<Button title="Change Value" onPress={() => setValue(value + 1)} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default App;
useRef
useRef
훅은 컴포넌트의 렌더링 사이에 값을 유지할 수 있게 해준다. 주로 DOM 요소 에 대한 참조를 저장하거나, 렌더링 간에 유지해야 할 값(예: 타이머 ID)을 저장하는 데 사용된다.
import React, { useRef, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
// useRef 훅을 사용하는 함수형 컴포넌트
const Timer = () => {
const countRef = useRef(0); // countRef를 선언하고 초기값 0을 설정
useEffect(() => {
const intervalId = setInterval(() => {
countRef.current += 1; // countRef.current 값을 증가시킴
console.log(`Timer: ${countRef.current}s`);
}, 1000);
return () => clearInterval(intervalId); // 컴포넌트 언마운트 시 인터벌 정리
}, []);
return (
<View style={styles.container}>
<Text style={styles.text}>Check the console for timer updates</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default Timer;
useImperativeHandle
useImperativeHandle
훅은 부모 컴포넌트가 자식 컴포넌트의 인스턴스 메서드와 속성에 접근할 수 있도록 해준다. 주로 forwardRef
와 함께 사용된다.
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// 자식 컴포넌트 정의
const Child = forwardRef((props, ref) => {
const [value, setValue] = useState(0);
useImperativeHandle(ref, () => ({
increment() {
setValue(prevValue => prevValue + 1); // 외부에서 호출 시 값 증가
},
getValue() {
return value; // 외부에서 호출 시 현재 값 반환
}
}));
return (
<View style={styles.container}>
<Text style={styles.text}>Value: {value}</Text>
</View>
);
});
// 부모 컴포넌트 정의
const Parent = () => {
const childRef = useRef();
return (
<View style={styles.container}>
<Child ref={childRef} />
<Button
title="Increment Child Value"
onPress={() => childRef.current.increment()} // 버튼 클릭 시 자식 컴포넌트 메서드 호출
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default Parent;
아래 예제는 컴포넌트와 훅을 종합적으로 사용하여 상태 관리, 부수 효과, 성능 최적화, 컨텍스트 및 참조 관리를 어떻게 하는지 보여준다.
import React, { useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef, createContext, forwardRef, useImperativeHandle } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
// Context 생성
const ThemeContext = createContext();
// 리듀서 함수 정의
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
// 컨텍스트 공급자 컴포넌트
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value=>
{children}
</ThemeContext.Provider>
);
};
// 자식 컴포넌트 정의
const Child = forwardRef((props, ref) => {
const [value, setValue] = useState(0);
useImperativeHandle(ref, () => ({
increment() {
setValue(prevValue => prevValue + 1);
},
getValue() {
return value;
}
}));
return (
<View style={styles.container}>
<Text style={styles.text}>Child Value: {value}</Text>
</View>
);
});
// ExpensiveComponent 컴포넌트 정의
const ExpensiveComponent = React.memo(({ value }) => {
const computedValue = useMemo(() => {
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
return sum;
}, [value]);
return <Text style={styles.text}>{`Computed Value: ${computedValue}`}</Text>;
});
// 메인 컴포넌트 정의
const App = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
const [value, setValue] = useState(0);
const childRef = useRef();
useEffect(() => {
const intervalId = setInterval(() => {
console.log('Interval running');
}, 1000);
return () => clearInterval(intervalId);
}, []);
const handleClick = useCallback(() => {
setValue(value + 1);
}, [value]);
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<ThemeProvider>
<View style={[styles.container, { backgroundColor: theme === 'light' ? 'white' : 'black' }]}>
<Text style=>Current Theme: {theme}</Text>
<Button title="Toggle Theme" onPress={toggleTheme} />
<Text style={styles.text}>Count: {state.count}</Text>
<Button title="Increment Count" onPress={() => dispatch({ type: 'INCREMENT' })} />
<Button title="Decrement Count" onPress={() => dispatch({ type: 'DECREMENT' })} />
<ExpensiveComponent value={value} />
<Button title="Change Value" onPress={handleClick} />
<Child ref={childRef} />
<Button title="Increment Child Value" onPress={() => childRef.current.increment()} />
</View>
</ThemeProvider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 20, // 텍스트 크기를 20픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
});
export default App;
이 예제는 다양한 훅을 사용하여 리액트 네이티브 애플리케이션에서 상태 관리, 성능 최적화, 부수 효과 처리, 컨텍스트와 참조 관리를 어떻게 하는지를 보여준다. 각 훅의 기능을 활용하여 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있다.
리액트 네이티브에서 Fetch API와 커스텀 훅은 데이터를 비동기적으로 가져오고 재사용 가능한 로직을 관리하는 데 중요한 역할을 한다. 이 두 가지를 깊이 있게 다루며, 각 개념과 그 사용법을 자세히 설명하겠다.
Fetch API는 웹에서 자원을 네트워크를 통해 가져오는 방법을 제공하는 자바스크립트 API이다. 리액트 네이티브에서도 데이터를 비동기적으로 가져올 때 널리 사용된다.
Fetch API를 사용하여 HTTP 요청을 보내고 응답을 처리하는 기본적인 방법이다.
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
// 데이터 Fetching을 위한 함수형 컴포넌트
const DataFetcher = () => {
const [data, setData] = useState(null); // 데이터 상태
const [loading, setLoading] = useState(true); // 로딩 상태
const [error, setError] = useState(null); // 에러 상태
useEffect(() => {
// 비동기 데이터 fetching 함수
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data'); // API 호출
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json(); // JSON 형식으로 응답 데이터 파싱
setData(result); // 상태 업데이트
} catch (error) {
setError(error); // 에러 상태 업데이트
} finally {
setLoading(false); // 로딩 상태 종료
}
};
fetchData(); // 데이터 fetching 호출
}, []); // 빈 배열을 전달하여 컴포넌트 마운트 시 한 번만 호출
if (loading) {
return <ActivityIndicator size="large" color="#0000ff" />; // 로딩 중 표시
}
if (error) {
return <Text style={styles.error}>Error: {error.message}</Text>; // 에러 메시지 표시
}
return (
<View style={styles.container}>
<Text style={styles.text}>Data: {JSON.stringify(data)}</Text> {/* 데이터를 문자열로 변환하여 표시 */}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 18, // 텍스트 크기를 18픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
error: {
color: 'red', // 에러 텍스트 색상을 빨간색으로 설정
},
});
export default DataFetcher;
POST 요청을 사용하여 데이터를 서버에 보내는 방법이다.
import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
const PostData = () => {
const [text, setText] = useState('');
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const handleSubmit = async () => {
try {
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text }), // 서버로 전송할 데이터
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json(); // JSON 형식으로 응답 데이터 파싱
setResponse(result); // 상태 업데이트
} catch (error) {
setError(error); // 에러 상태 업데이트
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Enter some text"
value={text}
onChangeText={setText}
/>
<Button title="Submit" onPress={handleSubmit} />
{response && <Text style={styles.text}>Response: {JSON.stringify(response)}</Text>}
{error && <Text style={styles.error}>Error: {error.message}</Text>}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
width: '80%',
marginBottom: 10,
paddingHorizontal: 8,
},
text: {
fontSize: 18, // 텍스트 크기를 18픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
error: {
color: 'red', // 에러 텍스트 색상을 빨간색으로 설정
},
});
export default PostData;
커스텀 훅은 리액트의 훅을 조합하여 재사용 가능한 로직을 만드는 방법이다. 훅을 재사용하고 컴포넌트 간의 상태나 로직을 공유할 때 유용하다.
커스텀 훅은 기존 훅을 조합하여 새로운 훅을 정의하는 방법이다. 예를 들어, API 호출과 관련된 로직을 커스텀 훅으로 추출할 수 있다.
import { useState, useEffect } from 'react';
// 커스텀 훅 정의
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
};
export default useFetch;
위에서 정의한 커스텀 훅을 사용하는 방법이다.
import React from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import useFetch from './useFetch'; // 커스텀 훅을 임포트
const DataFetcher = () => {
const { data, loading, error } = useFetch('https://api.example.com/data'); // 커스텀 훅 사용
if (loading) {
return <ActivityIndicator size="large" color="#0000ff" />;
}
if (error) {
return <Text style={styles.error}>Error: {error.message}</Text>;
}
return (
<View style={styles.container}>
<Text style={styles.text}>Data: {JSON.stringify(data)}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
text: {
fontSize: 18, // 텍스트 크기를 18픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
error: {
color: 'red', // 에러 텍스트 색상을 빨간색으로 설정
},
});
export default DataFetcher;
여러 커스텀 훅을 조합하여 더 복잡한 로직을 처리할 수 있다. 예를 들어, 입력 필드와 API 요청을 처리하는 훅을 조합할 수 있다.
import { useState } from 'react';
// 입력 필드의 값을 관리하는 커스텀 훅
const useInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
const handleChange = (newValue) => {
setValue(newValue);
};
return [value, handleChange];
};
export default useInput;
import React from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
import useFetch from './useFetch';
import useInput from './
useInput';
const PostData = () => {
const [text, setText] = useInput('');
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const handleSubmit = async () => {
try {
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setResponse(result);
} catch (error) {
setError(error);
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Enter some text"
value={text}
onChangeText={setText}
/>
<Button title="Submit" onPress={handleSubmit} />
{response && <Text style={styles.text}>Response: {JSON.stringify(response)}</Text>}
{error && <Text style={styles.error}>Error: {error.message}</Text>}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
width: '80%',
marginBottom: 10,
paddingHorizontal: 8,
},
text: {
fontSize: 18, // 텍스트 크기를 18픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
error: {
color: 'red', // 에러 텍스트 색상을 빨간색으로 설정
},
});
export default PostData;
import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet, ActivityIndicator } from 'react-native';
import useFetch from './useFetch';
import useInput from './useInput';
const DataForm = () => {
const [text, setText] = useInput('');
const { data, loading, error } = useFetch('https://api.example.com/data');
const [response, setResponse] = useState(null);
const handleSubmit = async () => {
try {
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setResponse(result);
} catch (error) {
setResponse(null);
setError(error);
}
};
return (
<View style={styles.container}>
{loading && <ActivityIndicator size="large" color="#0000ff" />}
{error && <Text style={styles.error}>Error: {error.message}</Text>}
{data && <Text style={styles.text}>Data: {JSON.stringify(data)}</Text>}
<TextInput
style={styles.input}
placeholder="Enter some text"
value={text}
onChangeText={setText}
/>
<Button title="Submit" onPress={handleSubmit} />
{response && <Text style={styles.text}>Response: {JSON.stringify(response)}</Text>}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 부모 컨테이너의 모든 공간을 차지하도록 설정
justifyContent: 'center', // 세로 방향으로 중앙 배치
alignItems: 'center', // 가로 방향으로 중앙 배치
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
width: '80%',
marginBottom: 10,
paddingHorizontal: 8,
},
text: {
fontSize: 18, // 텍스트 크기를 18픽셀로 설정
color: 'black', // 텍스트 색상을 검정색으로 설정
},
error: {
color: 'red', // 에러 텍스트 색상을 빨간색으로 설정
},
});
export default DataForm;