웹/개인 프로젝트

주가조회 웹사이트 7/28 업데이트 기록 (sns 공유 기능 등등)

공대생철이 2022. 7. 28. 21:32
728x90

 

 

7월 1주차 스프린트 회고 - 미국주식 주가조회 웹사이트

1일차 기획 단계. 1주일동안의 스프린트 주제를 정하는 거다보니 어디까지 해야될지 감도 잘 안 오고 어떤 걸 활용해야 될지도 잘 모르겠었다. 특히 API를 활용하여 웹사이트를 만들려고 컨셉을

selfdevelopcampus.tistory.com

이번 달 초에 했던 토이 프로젝트에서 티커를 입력하면 주가를 조회할 수 있는 웹사이트를 만듦.

 

2주에 걸쳐 추가할 수 있는 부분이 뭐가 있을까 고민했고 업데이트를 완료했다.

 

먼저 업데이트 사항으로는

- 입력값 유효성 검사

- 데이터 로드와 렌더링 사이의 시간 틈 제거

- SNS 공유 기능 추가

- not found page

- loading spinner 추가

 

입력값 유효성 검사

 

먼저 유효성 검사를 하기 전에 수정한 코드가 있음.

	const tickerInput = useRef();

tickerInput 값을 useState로 받아서 onChange로 만들어줬는데 이렇게 모든 입력마다 데이터를 업로드하는 현상이 발생해 로딩 시간 개선을 위해 ref로 받아왔다.

그리고 submit을 할 때 ref의 value를 읽어서 데이터를 로드하는 방식으로 수정.

 

	const checkValidInput = (value) => {
		if (value.trim().length === 0) {
			alert("티커를 입력해주세요.");
			return false;
		} else if (!/^[a-zA-Z]+$/.test(value)) {
			alert("올바른 티커를 입력해주세요.");
			tickerInput.current.value = "";
			return false;
		}
		return true;
	};

다음 1차 유효성 검사로 빈 입력과 알파벳이 아닌 입력을 했을 때를 만들어주었다.

 

빈 입력으로 submit을 하면 입력해달라는 메시지

알파벳이 아닌 입력값을 submit 하면 올바른 티커를 입력해달라는 메시지를 alert하도록 만들었다. 

 

그리고 얘를 통과하면 true를 리턴.

 

그 다음에 이제 데이터를 fetch 해야 함.

 

기존에는 주식 데이터와 뉴스 데이터 다른 함수로 불러와서 별개로 실행했는데 이 부분도 수정.

 

const fetchData = async (ticker) => {
		setFetchLoading(true);
		const res = await fetch(
			`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${ticker}&apikey=${process.env.NEXT_PUBLIC_STOCK_API_KEY}`
		);
		const newData = await res.json();
		console.log(newData["Global Quote"]);
		if (
			newData["Error Message"] ||
			Object.keys(newData["Global Quote"]).length === 0
		) {
			setFetchLoading(false);
			setFetchSuccess(false);
			setNewsData([]);
			return;
		}
		await fetchNewsData(ticker);
		setFetchLoading(false);
		setFetchSuccess(true);
		return setData(Object.values(newData["Global Quote"]));
	};

 

로딩인지 아닌지 하는 state는 일단 설명을 제끼고

 

먼저 주식에 대한 데이터를 로딩했을 때 데이터를 찾을 수 없으면

api에서 에러메시지나 빈 object를 출력하더라.

 

그래서 그 부분을 확인해서 데이터 fetch여부에 따라 fetchSuccess state를 변경하도록 코드를 바꾸었다.

			{!fetchLoading && fetchSuccess && (
				<Content
					stockData={firstFetch ? startingData : data}
					newsData={newsData}
				/>
			)}
			{!fetchLoading && !fetchSuccess && (
				<ErrorMessage errorType='no company found'></ErrorMessage>
			)}

그리고 success 여부에 따라 content 컴포넌트를 표시할지 error message를 표시할지 조건부로 렌더링

 

자 정리하면 이렇다.

 

빈 입력값 or 알파벳 확인 -> 그다음 티커 확인해서

존재하는 기업이면 data를 fetch해서 컴포넌트 만들고

실패하면 error message 출력

 

 

데이터 로드와 렌더링 사이의 시간 틈 제거

 

위의 유효성 검사 부분과도 연계가 되는데

fetchStockData와 fetchNewsData를 스크립트로 작성하니

화면에는 주식 데이터가 먼저 나오고 조금 이따가 뉴스가 나왔다.

 

렌더링 시간 일치가 안 돼어 매우 불편...

 

그래서 유효성 검사 로직 부분 다시 보면

	const fetchData = async (ticker) => {
    ...
    		const res = await fetch(
			...
		);
       if (
			newData["Error Message"] ||
			Object.keys(newData["Global Quote"]).length === 0
		) {
			......
			return;
		}
		await fetchNewsData(ticker);
        ...
        
        return setData(Object.values(newData["Global Quote"]));

 

이런 식으로 await을 한 번 더 걸었다. 

 

주식 데이터를 기다렸다가 받고 그 다음에 뉴스 데이터 받을 때까지 기다리고 setData로 데이터를 넣어주었다.

 

그렇게 되니깐 주식과 뉴스 데이터가 한 방에 setData로 들어가기 때문에 렌더링이 한 번에 되서 편-안.

 

SNS 공유 기능 추가

 

사실 대단한 거 있을 줄 알았는데 생각보다 별개 없었다.

 

https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fclipstock.vercel.app

https://twitter.com/intent/tweet?text=${sendText}&url=${sendUrl}

친절하게도 페이스북과 트위터는 이렇게 쉽게 공유할 수 있는 url을 만들어 놓았다.

 

자 그러면 뭐가 하나 빠진 느낌이 들지 않는가.

 

사실 하나는 아니고 인스타랑 카톡이 빠졌다.

 

인스타랑 카톡을 활용하는 디바이스는 대부분이 모바일이다.

모바일에서 활용할 수 있는 내장 공유 api를 찾았다.

 

바로 navigator.share

 

Navigator.share - Web API | MDN

Navigator.share() 메소드는 Web Share API 의 부분으로서 디바이스의 네이티브 공유하기 메커니즘을 작동시킨다. Web Share API 가 지원되지 않는다면, 이 메소드는 undefined 일 것이다.

developer.mozilla.org

const sendUrl = "https://clipstock.vercel.app/";

const shareData = {
	title: "미국주식 주가 조회",
	url: sendUrl,
};

const shareLink = async () => {
	try {
		await navigator.share(shareData);
	} catch (err) {
		console.log(err);
	}
};

이렇게 shareLink라는 함수를 만들어서 걸고

<a
	className='flex cursor-pointer visible md:invisible ml-auto sm:ml-0  bg-slate-300 p-2 rounded-md'
	onClick={shareLink}>
	Share
</a>

onClick으로 걸면 끝난다.

 

이게 모바일에서 어떻게 보이냐면

 

share 버튼을 부르면 이렇게 뜬다.

그래서 카카오톡이나 문자나 인스타나 url을 보낼 수 있다.

너무나 유용한 걸 알아내서 흐뭇.

 

not found page

		<section className='text-gray-600 body-font'>
			<div className='container px-5 py-24 mx-auto'>
				<div className='xl:w-1/2 lg:w-3/4 w-full mx-auto text-center'>
					<p className='leading-relaxed text-xl sm:text-3xl'>
						페이지를 찾을 수 없습니다.
					</p>
					<p className='text-lg mb-6'>인터넷 연결을 확인해보세요.</p>
					<Link href='/'>
						<a className='text-white bg-indigo-500 border-0  py-3  px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg'>
							다시 시도
						</a>
					</Link>
					<br />
					<span className='inline-block h-1 w-10 rounded bg-indigo-500 mt-8 mb-6'></span>
					<h2 className='text-gray-900 font-medium title-font tracking-wider text-sm'>
						<p className='text-gray-500'>문의사항</p>
						<Link href='mailto:jasonsc@korea.ac.kr'>
							<a>jasonsc@korea.ac.kr</a>
						</Link>
					</h2>
				</div>
			</div>
		</section>

not found 404 page는 위와 같이 만들었다.

 

별거는 없고 인터넷 다시 확인하라는 메시지

다시 시도하면 홈으로 다시 접속하게 하고

문의사항으로 이메일은 남기고 mailto를 걸어 누르면 바로 이메일을 보낼 수 있게 만들었다.

 

 

loading spinner 추가

 

로딩 스피너는 데이터 로딩 중에 빈 화면으로만 뜨지 않게 하기 위해 추가했다.

 

fetchLoading이라는 state를 활용해서 이 state가 true면 로딩 스피너가 등장할 수 있게 했다.

 

그래서 업데이트를 완료한 데모는 이렇다.

기존에 있던 거랑 크게 차이는 느껴지지는 않을 수도 있지만

코드가 매우매우 바뀌었고 그 안에서 의외로 고생을 많이했다....ㅋㅋㅋㅋ

 

https://github.com/manu1307/clipstock

 

GitHub - manu1307/clipstock

Contribute to manu1307/clipstock development by creating an account on GitHub.

github.com

 

깃헙에다가 쑥스럽지만 readme 까지 써서 업로드를 완료했다.

 

https://clipstock.vercel.app/

 

클립스탁

한국형 미국주식 주가조회

clipstock.vercel.app

 

기존에 있던 주소도 좀 드러워서 콕 집어주는 클립의 특성을 이용해 클립스탁이라는 이름으로 바꾸어주었다.

 

 

 

업데이트 하면서 배운 점

 

- state의 생명 주기에 대해 더 익숙해짐. 왜 안 변하지? 엄청 고민했던 시간이 길었는데 그게 다 함수 실행 과정 + state 생명주기가 꼬여서 그랬던 것이었다.

- async await에 대한 이해가 더 올라감. 보통 예제로 맨날 한 번만 하고 말았는데 스스로 코드 진행과정을 생각해서 await을 또 붙이는 연습.

- 기본 web api에서 share이라는 api를 활용하면 쉽게 공유를 할 수 있음. 이건 진짜 유용했다. 너무나 간단해서 발견하고 유레카를 외쳤음.

- state와 ref를 어떻게 활용해야할지 구분이 좀 됨. ref는 dom을 직접 다루는 거라 react에서 그렇게 권장하지는 않는다고 알고 있는데 그래도 활용하는 게 더 좋다고 생각이 들면 충분히 활용해봐도 좋을 듯.

- 페이스북, 트위터는 그냥 공유링크가 있음. 그거 그대로 복붙하고 내 웹사이트 url만 붙여주면 땡.

728x90