# 새 주제/답글 알림 클릭 후 주제 목록이 업데이트되지 않는 원인 찾음

**URL:** https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036
**Category:** Development
**Created:** [1월 16, 2022, 9:27오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036 "2022-01-16T21:27:09Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![th21](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/th21/32/211915_2.png) [@th21](https://meta.discourse.org/u/th21)
#### Post date: [1월 16, 2022, 9:27오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/1 "2022-01-16T21:27:09Z")

</div>

테마 크리에이터 사이트에서 무시한 사용자의 주제를 주제 목록에서 제거하려고 했습니다. 제 코드는 다음과 같습니다.

```plaintext
api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        this.topics = this.topics.filter(
          topic => !ignored.includes(topic.posters[0].user.username)
        );
      }
});

```

모바일과 데스크톱 모두에서 예상대로 잘 작동하지만, 새 주제/답글 알림을 클릭한 후 주제 목록이 업데이트되지 않는 문제도 발견했습니다.

이 버그를 재현하는 화면 녹화본이 있습니다.

영상에서 저는 데스크톱에서 모바일 뷰를 확인하면서 휴대폰으로 'test new topic alert 3’에 새 답글을 작성한 뒤, 데스크톱에서 알림을 클릭했습니다. 정상적인 경우라면 해당 주제가 목록 상단에 올라와야 하지만, 이 경우 그렇지 않습니다.

위에서 사용한 메서드가 잘못 트리거되는 줄 알았는데, 주제 알림을 클릭할 때 해당 메서드가 호출되지 않는 것을 확인했습니다.

이 버그가 발생한 원인에 대해 조언해 주실 분 계신가요? 감사합니다.

업데이트: 모바일 뷰에서 스크롤 시 추가 주제 자동 로딩 기능이 더 이상 작동하지 않는 문제도 발견했습니다.

---

<div class="post-metadata">

### Author: ![lucasbasquerotto](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lucasbasquerotto/32/133376_2.png) [@lucasbasquerotto](https://meta.discourse.org/u/lucasbasquerotto)
#### Post date: [1월 17, 2022, 3:36오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/2 "2022-01-17T15:36:42Z")

</div>

위에서 언급한 코드를 제거하면 무시된 사용자를 표시하지 않는 문제가 해결됩니까? 만약 해결된다면, 추측컨대 당신의 코드가 모든 사용자(또는 무시되어야 할 사용자보다 더 많은 사용자)의 토픽을 필터링하여 표시되지 않도록 만들고 있는 것 같습니다.

`ignored`에 어떤 값이 채워지는지는 알 수 없지만, 상단에 알림이 표시된 새 토픽을 생성한 사용자의 사용자명이 채워지고 있을 수 있습니다. 아니면 무시되지 말아야 할 사용자들로 채워지고 있는 것일 수도 있습니다. `ignored`에 존재하는 값들을 로그로 출력해 볼 수 있을까요?

---

<div class="post-metadata">

### Author: ![th21](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/th21/32/211915_2.png) [@th21](https://meta.discourse.org/u/th21)
#### Post date: [1월 17, 2022, 5:54오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/3 "2022-01-17T17:54:41Z")

</div>

이 문제는 모바일/모바일 뷰에서만 발생했기 때문에, 그런 상황은 아닌 것 같습니다. (bump가 되지 않고 더 이상 로드가 안 됨)

나는 ignore 기능을 사용할 수 있는 신뢰 수준에 도달하지 못했거나, 해당 기능이 비활성화되어 있다고 가정하여, 테마 제작자 사이트에서 테스트하기 위해 `const ignored = ['david', 'pekka_gaiser', 'sam'];`를 수동으로 설정했습니다.

그리고 bump를 시도한 주제는 내가 만든 주제입니다.

---

<div class="post-metadata">

### Author: ![lucasbasquerotto](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lucasbasquerotto/32/133376_2.png) [@lucasbasquerotto](https://meta.discourse.org/u/lucasbasquerotto)
#### Post date: [1월 17, 2022, 6:28오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/4 "2022-01-17T18:28:21Z")

</div>

> [@th21](#):
>
> 테마 제작자 사이트에서 테스트하기 위해 `const ignored = ['david', 'pekka_gaiser', 'sam'];`를 수동으로 설정했습니다.

이상하네요. 해당 코드 자체의 문제가 아니라면요. 코드를 다음과 같이 변경하면:

```plaintext
api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        this.topics = this.topics.filter(() => true);
      }
});

```

문제가 계속 발생합니까? 계속된다면 문제는 아마 다른 곳에 있을 것입니다.

---

<div class="post-metadata">

### Author: ![th21](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/th21/32/211915_2.png) [@th21](https://meta.discourse.org/u/th21)
#### Post date: [1월 17, 2022, 7:41오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/5 "2022-01-17T19:41:08Z")

</div>

아니요, 블록을 당신이 제공한 것으로 변경하면 버그가 사라집니다. 필터 함수가 토픽 데이터의 업데이트 주기를 깨뜨리는 건 아닌지 의심해 보았지만, 이 버그는 모바일에서만 발생하고 데스크톱과 모바일 간의 차이를 유발하는 원인을 파악하지 못하겠습니다…

---

<div class="post-metadata">

### Author: ![lucasbasquerotto](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lucasbasquerotto/32/133376_2.png) [@lucasbasquerotto](https://meta.discourse.org/u/lucasbasquerotto)
#### Post date: [1월 18, 2022, 12:39오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/6 "2022-01-18T12:39:31Z")

</div>

> [@th21](#):
>
> 아니요, 제가 제공한 내용으로 블록을 변경하면 버그가 사라집니다.

그렇다면 제가 이전에 말했듯이 `ignored` 변수가 잘못 채워지고 있는 것일 수 있습니다. 다른 곳에서 값이 변경되고 있을지도 모릅니다. 아래처럼 코드를 변경해 보세요:

```plaintext
api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        const ignored2 = ['david', 'pekka_gaiser', 'sam'];
        this.topics = this.topics.filter(
          topic => !ignored2.includes(topic.posters[0].user.username)
        );
      }
});

```

위 코드에서는 필터가 적용되는 동일한 스코프에 `ignored` 변수를 배치하고, 배열 값이 의도치 않게 변경되는 것을 방지하기 위해 변수 이름을 변경했습니다(예: 어딘가에서 `ignored.push(...)`를 호출하면 다른 곳에서도 그 값이 변경될 수 있음).

---

<div class="post-metadata">

### Author: ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)
#### Post date: [1월 18, 2022, 3:06오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/7 "2022-01-18T15:06:39Z")

</div>

이런 방식으로 코드를 작성하면

```javascript
this.topics = something_else

```

해당 프로퍼티를 다른 것으로 재정의하게 됩니다. 해당 프로퍼티를 감시(watch)하는 다른 것이 없다면 괜찮지만, 이 경우 `topics` 배열을 여러 곳에서 감시하고 있습니다.

예를 들어

> <https://github.com/discourse/discourse/blob/c1f74cd92af9a69e19cc6db416128df2d3aed5e7/app/assets/javascripts/discourse/app/components/topic-list.js#L50-L61>

개발 환경(development installation)에서 이렇게 하면, Ember가 콘솔에 다음과 같은 오류를 발생시킵니다.

 ![Ember console error. Attempting to update a tracked property](https://global.discourse-cdn.com/meta/original/3X/0/9/09d3e5ab6fd99cb92f00269a4e1d314c00d6df6c.png).

따라서 여기서 핵심은 대신 이렇게 하는 것입니다.

```javascript
this.set("topics", something_else)

```

`@tracked` 데코레이터가 Discourse에 도입될 때까지는요.

즉, 다음과 같은 코드를 시도해 보면

```javascript
api.modifyClass("component:topic-list", {
  @on("didReceiveAttrs")
  removeIgnoredUsers() {
    const filtered = this.topics.filter(
      topic => !ignored.includes(topic.posters[0].user.username)
    );
    this.set("topics", filtered);
  }
});

```

테마 크리에이터에서 데스크톱과 모바일 모두에서 작동해야 합니다.

하지만…

개발 환경에서 이 코드를 실행하면 또 다른 오류가 표시됩니다.

 ![Ember console error. Attempting to update a property used in the same computation](https://global.discourse-cdn.com/meta/original/3X/d/0/d031c66f7934fe46b4e585bdf3ccaeba195f18c6.png)

즉, 이는 여러분에게 무언가를 알려 줍니다. `topics` 배열은 여러 다른 곳에서 사용되고 있습니다. 따라서 이를 함부로 건드리는 것은 좋은 아이디어가 아닙니다. 특히 여러분의 사용 사례가 주로 시각적인 것이며 보안상의 문제가 관여되지 않으므로 더욱 그렇습니다.

제 제안은 다음과 같습니다: 한 발짝 물러서서 다른 접근 방식을 시도해 보세요. 배열을 수정하려는 대신, 훨씬 더 간단한 일을 하세요. 무시된 사용자가 해당 주제를 생성했다면, CSS 클래스를 추가하여 CSS로 이를 숨기세요.

아래와 같은 방식으로 수행할 수 있습니다. 따라 해 보고 싶으시면 몇 가지 주석을 남겨 두었으니, 사용하실 준비가 되면 삭제하시면 됩니다.

이것은 이니셜라이저 파일에 들어갑니다:

```javascript
import { apiInitializer } from "discourse/lib/api";
import discourseComputed from "discourse-common/utils/decorators";

export default apiInitializer("0.11.1", api => {
  // 수정 사항을 위한 id 설정
  const PLUGIN_ID = "hide-ignored-op-topics";

  // 추가하려는 클래스 이름. 앞의 공백은 필수입니다.
  const IGNORED_TOPIC_CLASS_STRING = " ignored-op-topic";

  // 현재 사용자 가져오기
  const user = api.getCurrentUser();

  // 로그인되지 않은 경우, 종료
  if (!user) {
    return;
  }

  // 무시된 사용자 목록 가져오기
  const ignored = user.ignored_users;

  // 코드 중복을 피하기 위한 헬퍼 함수
  const addIgnoredTopicClass = context => {
    // 코어/다른 플러그인 및 테마에서 가져온 클래스
    let classList = context._super(...arguments);

    // 조건 생성
    const shouldAddClass = ignored.includes(
      context.topic.posters[0].user.username
    );

    // 조건이 참이면 무시된 클래스 추가
    if (shouldAddClass) {
      classList += IGNORED_TOPIC_CLASS_STRING;
    }

    // 수정 사항이 있다면 classList와 수정 사항을 반환
    return classList;
  };

  // "최신" 페이지와 같은 기본 주제 목록에 클래스 추가
  api.modifyClass("component:topic-list-item", {
    pluginId: PLUGIN_ID,
    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass(this);
    }
  });

  // 카테고리 페이지의 주제 목록에도 동일하게 적용
  api.modifyClass("component:latest-topic-list-item", {
    pluginId: PLUGIN_ID,
    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass(this);
    }
  });
});

```

그리고 이것은 `/common/common.css`에 들어갑니다:

```scss
// load-more 기능에 영향을 주지 않으므로 여기서는 display: none;을 사용하지 않습니다.
.ignored-op-topic {
  height: 0;
  width: 0;
  position: fixed;
  bottom: 0;
}

```

---

<div class="post-metadata">

### Author: ![th21](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/th21/32/211915_2.png) [@th21](https://meta.discourse.org/u/th21)
#### Post date: [1월 19, 2022, 4:11오전 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/8 "2022-01-19T04:11:15Z")

</div>

감사합니다. 두 번째 방법이 작동합니다.

컴포넌트의 자식 요소에 추가 클래스를 붙일 수 있을까요?

> [@Johani](#):
>
> `component:latest-topic-list-item`

예를 들어, 주제 제목 오른쪽의 데스크톱 아바타 목록에서 무시된 사용자의 아바타를 숨기고 싶은데, 주제 목록 항목에 클래스를 추가하면 아바타 컴포넌트에도 클래스를 추가할 수 있을까요?

---

<div class="post-metadata">

### Author: ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)
#### Post date: [1월 20, 2022, 5:54오후 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/9 "2022-01-20T17:54:12Z")

</div>

위에서 사용한 `unboundClassNames()` 메서드는 컴포넌트 요소에 추가되는 클래스를 담당합니다. 즉, `.topic-list-item` 또는 `.latest-topic-list-item` HTML 요소를 의미합니다. 이는 여기에서

[discourse/app/assets/javascripts/discourse/app/components/topic-list-item.js at ad4faf637c9caf7e6ac60a614e3838a69c928e27 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/ad4faf637c9caf7e6ac60a614e3838a69c928e27/app/assets/javascripts/discourse/app/components/topic-list-item.js#L40)

그리고 여기에서 확인할 수 있습니다.

[discourse/app/assets/javascripts/discourse/app/components/latest-topic-list-item.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/1472e47aae5bfdfb6fd9abfe89beb186c751f514/app/assets/javascripts/discourse/app/components/latest-topic-list-item.js#L10)

Ember는 해당 메서드가 반환하는 문자열을 가져와 요소 자체의 `class` 속성으로 추가합니다.

해당 요소의 자식 요소에 클래스를 추가하려면 다른 방법을 사용해야 합니다.

`posters` 속성의 각 포스터는 `extras`라는 속성을 가지고 있습니다. 이 속성은 렌더링될 때 아바타에 추가될 클래스를 위한 플래그로 사용됩니다.

여기에서 설정되며

[discourse/app/assets/javascripts/discourse/app/models/topic-list.js at d3a59e3f695c467c22d02db62532194e17ac827b · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/d3a59e3f695c467c22d02db62532194e17ac827b/app/assets/javascripts/discourse/app/models/topic-list.js#L163)

여기에서 소비됩니다.

[discourse/app/assets/javascripts/discourse/app/templates/list/posters-column.hbr at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/1472e47aae5bfdfb6fd9abfe89beb186c751f514/app/assets/javascripts/discourse/app/templates/list/posters-column.hbr#L6)

따라서 해당 속성을 확장하면 조건에 따라 토픽 목록의 아바타에 클래스를 추가할 수 있습니다.

컴포넌트가 속성을 받을 때 메서드를 호출하여 이를 수행하려면 `@on` 데코레이터를 사용할 수 있습니다. 이미 해당 컴포넌트 클래스를 수정하고 있으므로, 위 코드에 이 새로운 동작을 통합할 수 있습니다.

최종적으로 다음과 같은 코드가 됩니다.

인셜라이저(initializer)에서

```javascript
import { apiInitializer } from "discourse/lib/api";
import discourseComputed, { on } from "discourse-common/utils/decorators";

export default apiInitializer("0.11.1", (api) => {
  const PLUGIN_ID = "hide-ignored-op-topics";
  const IGNORED_TOPIC_CLASS_STRING = " ignored-op-topic";
  const IGNORED_AVATAR_CLASS_STRING = " ignored-user-avatar";

  const user = api.getCurrentUser();

  if (!user) {
    return;
  }

  const ignoredUsers = user.ignored_users;

  function isIgnoredUser(poster) {
    return ignoredUsers.includes(poster.user.username);
  }

  function addIgnoredTopicClass() {
    let classList = this._super(...arguments);
    
    const topicCreator = this.topic.posters[0];

    if (isIgnoredUser(topicCreator)) {
      classList += IGNORED_TOPIC_CLASS_STRING;
    }

    return classList;
  }

  function addIgnoredAvatarClass() {
    this.topic.posters.forEach((poster) => {
      if (isIgnoredUser(poster)) {
        // default raw topic-lists
        poster.extras += IGNORED_AVATAR_CLASS_STRING;

        // categories page topic lists
        poster.user.set("extras", IGNORED_AVATAR_CLASS_STRING);
      }
    });
  }

  api.modifyClass("component:topic-list-item", {
    pluginId: PLUGIN_ID,

    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass.call(this);
    },

    @on("didReceiveAttrs")
    ignoredAvatarClass() {
      addIgnoredAvatarClass.call(this);
    },
  });

  api.modifyClass("component:latest-topic-list-item", {
    pluginId: PLUGIN_ID,

    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass.call(this);
    },

    @on("didReceiveAttrs")
    ignoredAvatarClass() {
      addIgnoredAvatarClass.call(this);
    },
  });
});

```

이것은 무시된 사용자가 시작한 토픽 목록 항목에 `ignored-op-topic` CSS 클래스를, 포스터 컬럼의 모든 무시된 사용자 아바타에 `ignored-user-avatar` CSS 클래스를 부여해야 합니다.

`.ignored-op-topic`에 대한 CSS는 위에서 이미 가지고 있습니다.

```scss
// load-more 동작을 방해하지 않으므로 display: none;을 여기서는 사용하지 않습니다.
.ignored-op-topic {
  height: 0;
  width: 0;
  position: fixed;
  bottom: 0;
}

```

이제 포스터 컬럼에서 무시된 사용자의 아바타를 숨기고 싶습니다.

> [@th21](#):
>
> 토픽 제목 오른쪽의 데스크톱 아바타 목록에서 무시된 사용자의 아바타를 숨기고 싶습니다.

그렇게 하지 마세요. 이는 많은 혼란을 초래할 것입니다.

무시된 사용자가 토픽에 답글을 작성하여 토픽이 위로 올라오(bump)는데, 아바타가 숨겨져 있다면 어떻게 될까요? 다른 누군가가 방금 토픽을 위로 올린 것처럼 보일 것입니다.

또한 카테고리 페이지의 토픽 제목 옆에는 아바타가 하나만 있습니다. 마지막 답글을 무시된 사용자가 작성한 경우 어떻게 될까요? 아바타가 없게 되나요?

이러한 사례들이 사용자에게 불쾌한 경험을 초래할 수 있음을 알 수 있습니다.

무시된 사용자의 아바타를 숨기는 대신, SVG 아이콘으로 교체할 수 있습니다. 모든 무시된 사용자는 동일한 아바타를 가지게 됩니다. CSS로 이를 수행할 수 있습니다.

```scss
.ignored-user-avatar {
  background: white;
  border: 1px solid transparent;
  box-sizing: border-box;
  opacity: 0.5;
  content: svg-uri(
    '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m256 0c141.385 0 256 114.615 256 256s-114.615 256-256 256-256-114.615-256-256 114.615-256 256-256zm0 105c-83.262 0-151 67.74-151 151s67.737 151 151 151 151-67.736 151-151-67.74-151-151-151zm-52.816 130.621a22.119 22.119 0 1 0 0-44.237 22.119 22.119 0 0 0 0 44.237zm127.749-22.121a22.116 22.116 0 0 0 -22.12-22.12 22.119 22.119 0 1 0 22.12 22.12zm-40.233 70.79a9.439 9.439 0 0 0 -13.35-13.347l-21.35 21.357-21.352-21.357a9.438 9.438 0 1 0 -13.348 13.347l21.352 21.352-21.352 21.358a9.438 9.438 0 1 0 13.347 13.347l21.353-21.355 21.351 21.351a9.439 9.439 0 0 0 13.349-13.343l-21.352-21.354z"/></svg>'
  );
}

```

그리고 다음과 같이 렌더링됩니다.

 ![ignored user avatar](https://global.discourse-cdn.com/meta/original/3X/1/a/1adb378e3ecba92bfb6a1dd1367e137d35375572.png)

`latest-topic-list-item`에서도 동일합니다. 원하는 아이콘으로 SVG를 변경하세요.

이 문제를 해결했으니…

질문에 답한 이유는 토픽 목록을 커스터마이징하는 방법과 이를 어떻게 수행하는지에 대해 이야기할 좋은 기회이기 때문입니다. 그러나 사용 사례에 대해 많은 우려가 있습니다. 무시된 사용자의 아바타를 숨길 필요가 있다는 것은 근본적인 문제가 있음을 시사합니다.

> “이 사람은 내가 관심 없는 주제에 대해 글을 씁니다. 노이즈를 줄이기 위해 이 사람을 무시하겠습니다.”

라고 말하는 것과

> “이 사람의 아바타를 보는 것만으로도 감정적 반응을 일으킵니다. 다시는 이 사람의 아바타를 보고 싶지 않습니다.”

라고 말하는 것은 전혀 다른 문제입니다.

당신은 누구보다 커뮤니티를 잘 알고 있지만… 아마도 살펴볼 가치가 있는 문제일 것입니다.

---

<div class="post-metadata">

### Author: ![th21](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/th21/32/211915_2.png) [@th21](https://meta.discourse.org/u/th21)
#### Post date: [1월 21, 2022, 3:21오전 UTC](https://meta.discourse.org/t/need-help-finding-why-topic-list-not-updating-after-click-new-topic-reply-alert/215036/10 "2022-01-21T03:21:09Z")

</div>

> [@Johani](#):
>
> 질문에 답변드린 이유는 주제 목록 커스터마이징과 그 방법에 대해 이야기할 좋은 기회라고 생각했기 때문입니다. 다만, 질문자님의 사용 사례에 대해서는 많은 우려가 있습니다.

알겠습니다. 저는 마스토돈이나 트위터처럼 블록 기능을 최대한 모방하려고 했습니다. 사용자를 무시하면 그 사용자의 콘텐츠를 다시는 볼 수 없게 되는 기능 말입니다. 대부분의 커뮤니티에서는 이런 기능이 필요하지 않을 수 있다는 점에 동의합니다. 하지만 제 사용자분들이 그 기능을 요청하고 계시므로, 최선을 다해 시도해 보고 싶습니다.
