아마도 너무 당연한 것을 놓치고 있는 것 같은데, 도저히 해결이 안 됩니다. 테마 컴포넌트가 여러 위젯을 로드하고 있으며, 사용자가 새 페이지로 이동한 후 위젯을 다시 렌더링하기 위해 다음 코드를 사용하고 있습니다(카테고리 배너에서 가져온 코드입니다).
api.decorateWidget("my-widget:after", (helper) => {
helper.widget.appEvents.on("page:changed", () => {
helper.widget.scheduleRerender();
})
});
하지만 이 코드는 새 페이지가 로드된 후에야 위젯을 업데이트합니다. 제가 원하는 것은 사용자가 다른 페이지로 이동하는 링크를 클릭하는 즉시 위젯 콘텐츠를 숨기는 것입니다. 네이티브 디스커스(Discourse) 기능이 클릭 즉시 콘텐츠를 숨기고 로딩 스피너를 표시하는 방식과 비슷하게 동작하길 바랍니다.
app\assets\javascripts\discourse\app\templates\discovery.hbs 파일에서 div 컨테이너가 “loading” 변수를 관찰하고 있는 것을 확인했지만, 이 변수가 어디서 오는지, 그리고 내 위젯에서 이 로딩 상태를 관찰하거나 해당 상태에 어떻게 접근할 수 있는지 파악하지 못하겠습니다.
답변이나 대략적인 방향을 알려주시면 감사하겠습니다.
감사합니다,
Zach
이 글 좀 올리고 싶어서요. 필요하다면 유료 프리미엄 지원을 구매해서라도 답변을 받고 싶습니다.
fzngagan
(Faizaan Gagan)
5월 19, 2021, 10:11오전
3
원하는 동작과 해당 정확한 페이지를 간략히 설명해 주시겠어요?
hawm
(Hawm)
5월 19, 2021, 11:16오전
4
scheduleRerender() 대신 queueRerender()를 사용해 볼 수 있습니다
eviltrout:
바인딩 및 콘텐츠 재렌더링
Ember를 꽤 오래 사용해 보셨다면, 위젯이 Ember의 바인딩이나 옵저버 시스템을 사용하지 않는데도 언제 재렌더링이 필요한지 어떻게 알 수 있는지 궁금하실 수 있습니다. 사실 이는 위젯이 취하는 주요 트레이드오프 중 하나입니다. Ember의 뷰 렌더링에서는 이 부분이 투명하게 처리되지만, 위젯의 경우 사용자가 위젯과 상호작용할 때만 재렌더링이 필요하다고 가정합니다.
위젯은 다음과 같은 경우 재렌더링됩니다:
사용자가 위젯을 클릭할 때
어떤 액션이 트리거된 후
액션이 프로미스를 반환하는 경우, 해당 프로미스가 리졸브된 후
위와 같은 경우는 Discourse가 위젯을 재렌더링해야 하는 경우의 대부분 을 차지합니다. 그러나 엣지 케이스가 있다면, 위젯은 this.queueRerender()를 호출하여 스스로 재렌더링할 수 있습니다.
렌더링 호출은 Ember Run Loop 에서 병합(coalesced)되므로, 같은 이벤트 루프 내에서 this.queueRerender()를 여러 번 호출하는 것을 두려워하지 마세요 – 큐에 추가된 모든 변경 사항에 대해 위젯은 한 번만 렌더링됩니다.
답변해 주셔서 감사합니다.
특정 카테고리 페이지용으로 제작한 위젯이 여러 개 있습니다. 이상적으로는 사용자가 페이지에서 이동하는 즉시 이 위젯들을 숨기고 싶습니다. 제가 원하는 동작을 보여주는 45초짜리 loom 영상 데모입니다: Google Chrome - Latest Rental Cities/California topics - Afford Anything Forums - Google Chrome | Loom
@hawm 이 경우 큐 재렌더링이 제가 필요한 것인지는 잘 모르겠습니다. 이는 위젯을 다시 렌더링하는 문제라기보다는, 전역 Discourse 앱이 새 페이지를 로드 중인지에 대한 인지 기능을 위젯에 부여하는 문제이기 때문입니다.
fzngagan
(Faizaan Gagan)
5월 19, 2021, 1:14오후
6
짧을수록 조건은 템플릿에 포함되어야 합니다. 예를 들어,
{{#if xyz}}
your code
{{/If}}
Ember 템플릿은 동적입니다. 값이 변경되면 위젯이 숨겨집니다.
네, 물론이죠. if/then 구문 자체는 잘 알고 있습니다. 제가 묻고 싶은 것은 현재 Discourse가 새 페이지를 로드하고 있는지 확인할 수 있는 방법이 있는지 하는 것입니다.
hawm
(Hawm)
5월 19, 2021, 4:11오후
8
modifyClass API를 사용하여 discovery 라우트에 해킹을 시도한 후 커스텀 이벤트를 트리거하면 작동할 것 같습니다.
https://api.emberjs.com/ember/3.12/classes/Route
loading 변수는 위에서 언급한 discovery 라우트에서 옵니다. 플러그인 아웃렛에 연결된 위젯은 인수로 전달되지 않기 때문에 해당 변수에 접근할 수 없을 수 있으며, 이는 플러그인 아웃렛의 정의에 따라 달라집니다.
네, 정말 감사합니다. 알아볼 게 있어서 조사해보고, 만약 해결책을 찾게 되면 후인을 위해 이 글에 업데이트하겠습니다
드디어 해결책을 찾았습니다. 이 문제를 해결하는 데 정말로 너무 오랜 시간을 보냈고, 제 생각에는 솔직히 코어에 이미 이런 기능이 있어야 하지 않나 싶을 정도로 자연스러운 해결책이라 코어에 머지하는 것이 가치가 있다고 봅니다.
아래 코드를 제 테마 컴포넌트에 추가했는데, 이 코드는 라우팅이 시작되는 즉시 body에 “loading” 클래스를 추가하고, 라우팅이 완료되는 즉시 해당 클래스를 제거합니다. Ember에 익숙한 분들에게는 단순하고 자명해 보일 수 있지만, 저는 이걸 파악하는 데 터무니없이 오랜 시간이 걸렸습니다(수많은 시도를 하고, 여기에서 찾을 수 있는 모든 스레드를 읽어가며 말이죠).
이 코어 코드가 자리 잡으면, body 태그에 loading CSS 클래스가 있는지 여부에 따라 CSS와 표시 여부가 제어되도록 다양한 위젯에 로딩 스피너 등을 추가할 수 있습니다.
initialize() {
withPluginApi("0.8.8", (api) => {
const router = api._lookupContainer('router:main');
router.reopen({
addLoadingCSSClassToBody: function() {
document.body.classList.add("loading");
}.on('willTransition')
});
router.reopen({
removeLoadingCSSClassFromBody: function() {
document.body.classList.remove("loading");
}.on('didTransition')
});
});
},
};
공유하는 코드는 위젯에서 가져온 것이 아니라, 여기에서 다운로드를 위해 출시한 컴포넌트에서 가져온 것입니다.
여기서는 라우터를 사용하고, @discourseComputed를 통해 라우트가 변경되었는지 확인한 후 그에 따라 렌더링을 수행합니다.
동작 원리에 관심이 있으시면 코드를 더 자세히 살펴볼 수 있습니다.