stackflow icon indicating copy to clipboard operation
stackflow copied to clipboard

react구현체쪽에서 freeze설정 옵션이 들어가면 좋을 것 같습니다

Open YangJonghun opened this issue 3 years ago • 3 comments

전역적으로 context가 앱 전체를 감싸고 있고, 모든 acitivty들이 해당 context의 변화를 감지해야한다고 할 때, 보여지지 않는 화면은 사실 불필요한 render로직이 돌아가는 상황이기 때문에 children을 조작하는 등의 처리로 불필요한 컴포넌트 로직호출을 피할 수 있다면 좋을 것 같습니다. (현재는 스택전체가 display:none처리가 되어있기 때문에 reflow관련 문제는 없겠지만 사용하는 쪽에서 변경되는 상태에 따라 무거운 로직을 돌린다던지, activity 스택이 과하게 쌓였다던지 하는 경우에 퍼포먼스 이슈가 있을 수 있을 것 같습니다)

react-native쪽에서 주로 사용되는 react-native-screens는 react-freeze로 위 이슈를 해결하고 있습니다. 당근의 stackflow에서도 이를 사용하거나, 혹은 편하신 렌더링 suspend처리를 구현하신 뒤 사용자에게 freeze설정 on/off옵션을 제공한다면 유용할 것 같아 이슈남깁니다

(혹시 react구현체쪽의 로직보단 별도 plugin에서 구현하는 것이 설계원칙에 부합하다고 생각되신다면 close해주세요~)

YangJonghun avatar Oct 30 '22 13:10 YangJonghun

안녕하세요! 혹시 플러그인에 존재하는 wrapActivity() API로 react-freeze를 사용해서 감싸면 될거같은데요. (isActive 또는 isTop 플래그를 통해서 freeze 여부를 판단) 혹시 이렇게는 힘들까요??

const reactFreezePlugin = () = () => ({
  key: "react-freeze-plugin",
  wrapActivity({ activity }) {
    // ...
  }
})
stackflow({
  // ...
  plugins: [
    reactFreezePlugin(),
  ]
})

tonyfromundefined avatar Nov 10 '22 01:11 tonyfromundefined

답변 감사드려요!

wrapActivity()에서 제공해주시는 activity상태만을 사용해서 처리하기엔 아래와 같은 어려운 부분이 있을 것 같습니다.

freeze(덮여진 activity들의 fallback처리)는 트랜지션이 끝나고 완전히 덮여진 순간에 동작해야만 합니다.

그래야 유저에게 트랜지션 중 정상적인 activity를 보여줄 수 있기 때문인데 이를 위해선 wrapActivity() API에서 최상단 activity의 트랜지션이 끝나는 시점을 감지해야합니다.

하지만 isTop이나 isActive플래그의 경우 transition이 시작되는 순간 false로 변환되기때문에 적합하진 않았습니다.

(useStyleEffectHide에서 display = "none"처리가 되는 시점과 동일한 조건에 freeze처리를 해줘야하는데 wrapActivity에서 제공해주는 값들만으론 이를 처리하기가 애매한것같습니다🥲)

대신 아래와 같이 wrapping component를 추가해 useStack hook의 transitionDuration값을 이용해 트릭을 쓰는 아래와 같은 방법은 가능할 것 같습니다.

function DelayedFreeze({ freeze, children }: FreezeWrapperProps) {
  const [freezeState, setFreezeState] = React.useState(false);
  const stack = useStack();

  if (freeze !== freezeState) {
    setTimeout(() => {
      setFreezeState(freeze);
    }, stack.transitionDuration);
  }

  return <Freeze freeze={freeze ? freezeState : false}>{children}</Freeze>;
}

const reactFreezePlugin: StackflowReactPlugin = ({ initContext }) => ({
  key: "react-freeze-plugin",
  wrapActivity({ activity }) {
    const shouldFreeze = !activity.isActive && !activity.isTop;
    return (
      <DelayedFreeze freeze={shouldFreeze}>{activity.render()}</DelayedFreeze>
    );
  },
});

YangJonghun avatar Nov 10 '22 18:11 YangJonghun

아 맞네요! 그리고 추가로 스와이프백 동작에서 freeze를 풀어줘야되겠네요. 고민해보겠습니다!

tonyfromundefined avatar Nov 11 '22 05:11 tonyfromundefined