iOS에서 뒤로 가기 전환시 스크롤링 포지션 이슈 (route, scrollTop)

최근에 react.js 로 구현된 어플리케이션에서 페이지 이동 후 뒤로 가기 위한 행동을 하면 스크롤 포지션이 엄하게 바뀌는 경우를 대처하기 위해 이런 저런 방법을 찾아 본 뒤 원인을 찾게 되었다.

iOS에서 앵커 태그(a) 가 아닌 이동일 경우에 생기는 이슈인 듯 하다.
예) this.props.history.push(‘/main’);
리액트 라우터를 이용해 페이지가 전환되었을 경우 생기는 데 기존 프로젝트에 보니 route에 scrolltop이라는 컴포넌트를 보고 여기를 손 봐야할 것 같아서 해외 사례를 찾아보니 아래 링크에 댓글로 해결 방법 실마리를 얻을 수 있었다.

https://spectrum.chat/react/general/handling-scroll-position-on-route-changes~1e897a67-c05f-40c0-946b-d459d93615bf

그런데 이 코드 중에 단점은 로딩 후 첫 진입 페이지의 경우의 스크롤 위치값을 못 체크하는 것 같았다.
이유를 찾아보니 리액트 라우트 전환 시 라이프 사이클에서componentDidUpdate(prevProps) 를 통해 이전 페이지의 포지션값을 이전 페이지의 경로 이름을 지정해서 저장해야하는 데 render 호출해서 페이지를 새로 이동된 페이지를 읽고 componentDidUpdate를 호출 하니 당연히 새로 페이지 렌더하니 스크롤이 최상단으로 올라갔고 그 상태에서 이전 경로의 위치값을 저장하려니 0으로 저장시켜서 뒤로 가도 기존 스크롤 위치가 아닌 0의 값으로 저장되어서 제대로 안먹힌거 였다.
쉽게 말해 라이프 사이클 componentDidUpdate와 render 순서 이슈다.

그래서 아래처럼 수정해서 적용했다.

class ScrollToTop extends Component {
	saveScrollPosition = {};
	temp = [];
	prevPathNameArr = [];

	componentWillMount() {
		if ("scrollRestoration" in window.history) {
			window.history.scrollRestoration = "manual"
		}
		console.log('scrollTop.js - willMount')
		// window.scrollTo(0, 0)
	}

	componentDidMount() {
		this.prevPathNameArr.push(this.props.location.pathname);
	}
	componentDidUpdate(prevProps) {
		const {
			history: { action },
			location: { pathname: newPath = "root" }
		} = this.props;

		const {
			location: { pathname = "root" }
		} = prevProps;

		if(action === 'POP') {
			const pos = this.saveScrollPosition[this.props.location.pathname];
			if (pos) {
				setTimeout(() => window.scrollTo(pos[0], pos[1]), 50);
				this.prevPathNameArr.push(this.props.location.pathname);
			}
		}else if(action === 'PUSH'){
			this.saveScrollPosition[prevProps.location.pathname] = this.temp[ this.props.location.pathname];
			setTimeout(() => window.scrollTo(0,0), 50);
		}
	}
	render() {
		(() =>{
			const {
				history : { action },
				location : { pathname : pathname }
			} = this.props;
			if(action === 'PUSH'){
				this.temp[ this.props.location.pathname ] = [window.pageXOffset, window.pageYOffset];
			}
		})()
		 return null
	}
}
export default withRouter(ScrollToTop)

render에서 위치값을 임시로 temp에 저장해 두고 componentDidUpdate 에서 그 값을 가져다가 저장하는 것이다.

TOP