0

I'm trying to filter posts by category for a blog that uses React. Here is what the data looks like:

const posts = [
  {
    "categories": [
      {
        "title": "tag1"
      },
      {
        "title": "tag2"
      },
      {
        "title": "tag3"
      }
    ],
    "title": "First post",
    // more stuff here
  },
  {
    "categories": [
      {
        "title": "tag2"
      },
      {
        "title": "tag3"
      },
      {
        "title": "tag4"
      },
      {
        "title": "tag5"
      }
    ],
    "title": "Second post"
    // more stuff here
  },
  {
    "categories": [
      {
        "title": "tag1"
      },
      {
        "title": "tag3"
      },
      {
        "title": "tag4"
      }
    ],
    "title": "Third post"
    // more stuff here
  },
  {
    "categories": [
      {
        "title": "tag1"
      },
      {
        "title": "tag2"
      },
      {
        "title": "tag4"
      },
      {
        "title": "tag5"
      }
    ],
    "title": "Fourth post"
    // more stuff here
  }
]

I have a piece of state called filter that updated from a <select> menu, which looks like this: const [filter, setFilter] = useState('all');

How would I write the rest of this code block?

useEffect(() => {
  if (filter !== 'all') {
    // Not sure what to do here
}
}, [])

Not sure if I use filter on the first array, or do I keep using filter all the way down? I've tried a bunch of things, but haven't been able to get it to work.

2
  • 1
    Looks like this doesn't need to be inside an effect, you can just filter in the component. Also, what's in the select? Is it tags? Commented Jul 19, 2020 at 2:10
  • 1
    @Nick is right, if you're array is in the state, then what you need is a selector which filters the array based on a category instead of an effect, but if the array is in the component then you can just filter the array in the component. Commented Jul 19, 2020 at 2:28

1 Answer 1

1

This is how you can filter an object like that:

const posts = [
  {
    "categories": [
      {
        "title": "tag1"
      },
      {
        "title": "tag2"
      },
      {
        "title": "tag3"
      }
    ],
    "title": "First post"
  },
  {
    "categories": [
      {
        "title": "tag2"
      },
      {
        "title": "tag3"
      }
    ],
    "title": "Second Post"
  }
];

const filter = "tag1";

const filtered = posts.filter(post => {
  return post.categories.some(cat => cat.title === filter)
});

console.log(filtered);

Now in a functional component, there's really no need to use an effect, this is simple run on your state every time the component is rendered:

function MyComponent() {
  const [filter, setFilter] = useState("all");

  const filtered =
    filter === "all"
      ? posts
      : posts.filter((post) => {
          return post.categories.some((cat) => cat.title === filter);
        });

  return <>Render stuff here</>
}

If your component updates a lot and the filter is running too much, you can look into using a useMemo hook to memoize the value until the filter changes.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Nick! That makes a lot of sense. I've got it working now 😊

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.