초대 코드나 지갑 주소, 쿠폰 번호처럼 사용자가 어딘가에 옮겨 붙일 값이 있으면 "복사" 버튼이 하나쯤은 필요해진다. 웹이라면 navigator.clipboard를 쓰면 되는데, React Native에는 그런 게 없다. 예전엔 @react-native-clipboard/clipboard를 별도로 붙였는데, Expo 프로젝트라면 expo-clipboard 하나로 끝난다.
설치
npx expo install expo-clipboard
복사하기
setStringAsync에 문자열을 넘기면 끝이다. 비동기 함수라서 await을 붙인다.
import * as Clipboard from 'expo-clipboard';
async function copyCode(code: string) {
await Clipboard.setStringAsync(code);
}
문제는 복사가 됐는지 사용자가 알 수가 없다는 거다. 아무 반응이 없으면 버튼이 먹혔는지 의심하게 된다. 그래서 복사 직후에 "복사됨" 상태를 잠깐 보여주는 패턴을 거의 항상 같이 쓴다.
const [copied, setCopied] = useState(false);
async function handleCopy() {
await Clipboard.setStringAsync('WELCOME2026');
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}
// <Pressable onPress={handleCopy}>
// <Text>{copied ? '복사됨 ✓' : '코드 복사'}</Text>
// </Pressable>
여기에 expo-haptics로 살짝 진동을 얹으면 "됐다"는 느낌이 확실해진다.
붙여넣기
반대로 클립보드에 있는 값을 읽어오는 것도 된다. 붙여넣기 버튼이나 OTP 자동 입력에 유용하다.
async function pasteFromClipboard() {
const text = await Clipboard.getStringAsync();
if (text) setInput(text);
}
미리 뭔가 들어있는지만 확인하고 싶을 땐 hasStringAsync()를 쓰면 실제 내용을 읽지 않고도 확인할 수 있다. iOS에서는 클립보드를 읽을 때 상단에 붙여넣기 알림이 뜨는데, 이 함수는 그걸 띄우지 않아서 "붙여넣기" 버튼을 조건부로 노출할 때 딱 맞다.
const canPaste = await Clipboard.hasStringAsync();
이미지도 된다
텍스트뿐 아니라 이미지도 다룰 수 있다. 스크린샷을 클립보드에 넣거나, 붙여넣은 이미지를 받아올 때 쓴다.
await Clipboard.setImageAsync(base64Image);
const image = await Clipboard.getImageAsync({ format: 'png' });
// image?.data 는 data URI 형태로 온다
정리
- 복사는
setStringAsync, 읽기는getStringAsync— 둘 다 비동기다. - 복사 후에는 반드시 시각적 피드백을 줘라. 상태 토글 + 타이머 조합이면 충분하다.
- 읽기 전 확인은
hasStringAsync로. iOS 붙여넣기 알림을 안 띄운다.
버튼 하나 붙이는 일이지만, 피드백을 빼먹으면 완성도가 확 떨어진다. 이 작은 부분이 앱이 "제대로 만들어졌다"는 인상을 좌우한다.