javascriptjsonreact-hooksresponsiveuse-reducer

Changing JSON data source at certain viewport in react


I am working on a project using react where I plug in data from a JSON file into a reducer function to manage the content state. However, at a certain viewport, another image is provided that needs to be displayed instead of the other image. If I am using useReducer, how can I change the image source once a certain viewport is reached? Attached are snippets from my code

Example of JSON data source:

    {
    "name": "Starry Night",
    "year": 1889,
    "description": "Although The Starry Night was painted during the day in Van Gogh's ground-floor studio, it would be inaccurate to state that the picture was painted from memory. The view has been identified as the one from his bedroom window, facing east, a view which Van Gogh painted variations of no fewer than twenty-one times, including The Starry Night. \"Through the iron-barred window,\" he wrote to his brother, Theo, around 23 May 1889, \"I can see an enclosed square of wheat ... above which, in the morning, I watch the sun rise in all its glory.\"",
    "source": "https://en.wikipedia.org/wiki/The_Starry_Night",
    "artist": {
      "image": "../assets/starry-night/artist.jpg",
      "name": "Vincent Van Gogh"
    },
    "images": {
      "thumbnail": "../assets/starry-night/thumbnail.jpg",
      "hero": {
        "small": "../assets/starry-night/hero-small.jpg", //This is mobile
        "large": "../assets/starry-night/hero-large.jpg"  //This is for tablet and up
      },
      "gallery": "../assets/starry-night/gallery.jpg"
    }
  },

// Where image is rendered using useState():

<ImageWorks
      className="gallery__image"
      source={state.image}
      alt={`"${state.name}" by ${state.artist}, ${state.year}`}
    />

// How state is managed with useReducer():

   const [i, setIndex] = useState(0)
  const contentReducer = (state, actions) => {
    switch (actions.type) {
      case ACTIONS.UPDATE:
        return {
          ...state,
          image: data[i].images.hero.small,
          name: data[i].name,
          artist: data[i].artist.name,
          artistImg: data[i].artist.image,
          year: data[i].year,
          description: data[i].description,
          source: data[i].source,
        }
      default:
        return state
    }
  }
  const [state, dispatch] = useReducer(contentReducer, {
    image: data[0].images.hero.small,
    name: data[0].name,
    artist: data[0].artist.name,
    artistImg: data[0].artist.image,
    year: data[0].year,
    description: data[0].description,
    source: data[0].source,
  })

So for example, I would need to change the image from 'data[0].images.hero.small' to 'data[0].images.hero.large' once my viewport is met.

Thanks for the help!


Solution

  • solved my own issue

    easily achieved with this media query package: https://www.npmjs.com/package/react-responsive

    read the documentation on how to implement, in my case, this is how I would use it:

    const isMobile = useMediaQuery({ query: '(max-width: 375px)' })
    
    const [state, dispatch] = useReducer(contentReducer, {
        imageMobile: data[0].images.hero.small, // set below 375px
        imageLarge: data[0].images.hero.large, // set above 375px
        name: data[0].name,
        artist: data[0].artist.name,
        artistImg: data[0].artist.image,
        year: data[0].year,
        description: data[0].description,
        source: data[0].source,
      })
    
    <ImageWorks
          className="gallery__image"
          source={isMobile ? state.imageMobile : state.imageLarge} // ternary
          alt={`"${state.name}" by ${state.artist}, ${state.year}`}
        />