Glidarn
Glidarn

Reputation: 285

Vuex state structure and fetching when using same type of data with different values on different routes

I'm creating a portfolio with vue, vuex and vue-router that will show images.

On the homepage i will show images with 'show_home: true'.

Then there is "tag" pages (portfolio/:tagSlug) that will show images based on a slug, eg. 'weddings' with infinite scroll (auto populate pagination).

An image object will look something like:

{
   id: 1,
   title: 'Lorem..',
   path: '..',
   show_home: true
   tags: [ {id: 1, slug: 'weddings'} ]

},
{
   id: 2,
   title: 'Lorem2..',
   path: '..',
   show_home: false
   tags: [ {id: 1, slug: 'weddings'}, {id: 2, slug: 'water'} ]

}

Endpoints examples:

Homepage: GET: ../images/homepage?p=1 
Tag page: GET: ../images/:slug?p=1

I can't figure out how I should structure this in vuex and handle the fetching..

Should i just create i single 'images: []' state and populate it with ALL the images after fetching them from the api in each route, then filter them with getters? How can i get the pagination in there in that case? Or do you have a better solution?

Thanks in advance

Upvotes: 0

Views: 139

Answers (1)

retrograde
retrograde

Reputation: 2979

My preferred approach is to "flatten" the relationships and pull them as needed. This also allows you to only pull what you need from the server or related modules.

tags vuex module:

all: {
  1: {  <-- indexed by tag id
    name: "weddings"
    images: [1,2,3,4] <-- image ids
   }
  }
active: false  <-- When there is an active tag, this becomes the id of the tag.

The vuex images module would follow this same pattern:

 all: {
  1: {  <-- indexed by image id
    title: 'Lorem..',
    path: '..',
    show_home: true
    tags: [1,2,3,4] <-- tag ids
   }
  }
active: false  <-- When there is an active image, this becomes the id of the image.

Then use a getter to hydrate the images or tags from the respective vuex module.
There is a great write up on this approach on this blog: https://medium.com/js-dojo/structuring-vuex-modules-for-relationships-speed-and-durability-de25f7403643

With this approach you will have fewer and smaller api calls, pagination is manageable and you don't need to worry about stale data in your relationships.

EDITED -- API info:

Two approaches come to mind. 1) always load the images with the tag.

Tag index request would not load any images, just the basic info for each tag.

When the user clicks on a tag, this inits an API call for the tag details:

Tag show request (tags/1 or tags/weddings) would return the tag with loaded relationships:

public function show($id)
{
    $tag = Tag::where('id', $id)->with('images')->firstOrFail();
    return new TagResource($tag);  <-- will have all related images loaded. 
}

2) set up a nested REST endpoint if needed

You can use the the resource controllers to shortcut the boilerplate like this:

api.php

Route::apiResource('tags.images', 'tags\TagImageController');

This route will watch your api calls and determine if it is index/store/show/delete. From your front end you can make a call like https://backendsite.com/tags/1/images (If wedding tag has an id of 1)

Then in the TagImageController you would have something like this:

public function index(Request $request, $id)
{
    $tag = MemTag::find($id);
    $images = $tag->images()->get();
    $images->load(Image::allowedIncludes); <- or you can manually list relationships you want to load

    return ImageResource::collection($images);
}

Upvotes: 1

Related Questions