Home > Back-end >  Changing image based on index, using ImageId
Changing image based on index, using ImageId

Time:01-08

I'm using street views from Mapillary.js and depending on an image key, passed as a prop, I want to show different images/street views. I've tried to do it with a conditional (ternary) operator like this:

<Mapillary width="auto" height="94vh" imageId={currentClue === 0 ? '2978574139073965' : currentClue === 1 ? '461631028397375' : currentClue === 2 ? '2978574139073965' : currentClue === 3 ? '312627450377787' : currentClue === 4 ? '695710578427767' : ''} />

Right now though, I only see the first image (when currentClue === 0). When currentClue === 1, the first image is still showing, although I can see in the console that the currentClue index is ascending.

I've also tried to change image by saving imageId in state and using it like this:

  const handleClick = () => {
    setCurrentClue(currentClue   1);
    if (currentClue < 4) { //*  Show alert if clue index > 4
      setLevel(level - 1);
      if (currentClue === 1) setImageId('461631028397375')
      if (currentClue === 2) setImageId('2978574139073965')
    } else {
      swal('Time to make a guess!', {
        button: 'OK'
      });
    }
    dispatch(game.actions.setScore(currentScore - 1));
  };
But get the same result: First image is showing, but not the second. Does anyone have any suggestions on how to get it to work?

This is the whole component where I'm trying to do this:

import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { game } from 'reducers/game';
import swal from 'sweetalert';

import { Mapillary } from 'components/Mapillary/Mapillary';
import { Paragraph } from 'GlobalStyles';
import { MapillaryContainer, ClueContainer, SpecialSpan, ClueParagraph, AnotherClueButton } from './Clues.Styles'

export const Clues = () => {
  const [games, setGames] = useState([])
  const [loading, setLoading] = useState(false);
  const [currentClue, setCurrentClue] = useState(0);
  const [level, setLevel] = useState(5);
  // const [imageId, setImageId] = useState('2978574139073965')

  //* Fetching clues
  const fetchClues = () => {
    setLoading(true);
    fetch('https://final-project-api-veooltntuq-lz.a.run.app/games')
      .then((response) => {
        return response.json()
      })
      .then((response) => {
        setGames(response.games)
      })
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
  }

  //* Setting current score
  const currentScore = useSelector((store) => store.game.score);
  const dispatch = useDispatch();

  const handleClick = () => {
    setCurrentClue(currentClue   1);
    if (currentClue < 4) { //*  Show alert if clue index > 4
      setLevel(level - 1);
    /*     if (currentClue === 1) setImageId('461631028397375')
      if (currentClue === 2) setImageId('2978574139073965') */
    } else {
      swal('Time to make a guess!', {
        button: 'OK'
      });
    }
    dispatch(game.actions.setScore(currentScore - 1));
  };

  useEffect(() => {
    fetchClues()
  }, [])

  const activeClue = games[currentClue];

  if (loading) {
    return <Paragraph>Loading clues...</Paragraph>
  }

  if (currentClue < 5) { //* Stop showing clues after clue 5
    return (
      <div>
        <MapillaryContainer>
          {console.log(currentClue)}
          <Mapillary width="auto" height="94vh" imageId={currentClue === 0 ? '2978574139073965' : currentClue === 1 ? '461631028397375' : currentClue === 2 ? '2978574139073965' : currentClue === 3 ? '312627450377787' : currentClue === 4 ? '695710578427767' : ''} />
        </MapillaryContainer>
        <ClueContainer>

          <SpecialSpan>Level: {level}</SpecialSpan>
          <ClueParagraph>{activeClue && activeClue.gameOne}</ClueParagraph>

          <AnotherClueButton type="button" onClick={() => handleClick()}>I need another clue</AnotherClueButton>
        </ClueContainer>
      </div>
    )
  }
}

EDIT: This is the Mapillary component:

import React, { Component } from 'react';
import { Viewer } from 'mapillary-js';

class ViewerComponent extends Component {
  constructor(props) {
    super(props);
    this.containerRef = React.createRef();
  }

  componentDidMount() {
    this.viewer = new Viewer({
      accessToken: this.props.accessToken,
      container: this.containerRef.current,
      imageId: this.props.imageId
    });
  }

  componentWillUnmount() {
    if (this.viewer) {
      this.viewer.remove();
    }
  }

  render() {
    return <div ref={this.containerRef} style={this.props.style} />;
  }
}

export const Mapillary = (props) => {
  return (
    <ViewerComponent
      accessToken={process.env.REACT_APP_MAPILLARY_CLIENT_TOKEN}
      imageId={props.imageId}
      style={{ width: props.width, height: props.height }} />
  );
}

CodePudding user response:

I think your second method will be work, the error is that you are adding and checking the currentClue value in the same function, your state is not updated, you have to use useEffect it will detect the change of currentClue state and change the image according to your state value, I hope it works.

here is one more thing you just need to handle the dispatch according to your requirements because useEffect will be called once your component load.

const handleClick = () => {
    const val = currentClue   1;
    setCurrentClue(val);
};

useEffect(() => {
    if (currentClue < 4) { //*  Show alert if clue index > 4
    setLevel(level - 1);
    if (currentClue === 1) setImageId('461631028397375')
    if (currentClue === 2) setImageId('2978574139073965')
    } else {
    swal('Time to make a guess!', {
        button: 'OK'
    });
    }
    dispatch(game.actions.setScore(currentScore - 1));
}, [currentClue])

CodePudding user response:

Well, in ViewerComponent you only create the viewer once, on component mount, so subsequent changes to it are not used anywhere.

Now if you read the docs for the imageId option, it states

Optional image-id to start from. The id can be any Mapillary image. If a id is provided the viewer is bound to that id until it has been fully loaded. If null is provided no image is loaded at viewer initialization and the viewer is not bound to any particular id. Any image can then be navigated to with e.g. viewer.moveTo("<my-image-id>").

So, you will have to add a componentDidUpdate(prevProps) to the ViewerComponent and check if the update has a new imageId and act accordingly.

componentDidUpdate(prevProps){
  if (prevProps.imageId !== this.props.imageId) {
    if (this.viewer) {
      this.viewer.moveTo(this.props.imageId);
    }
  }
}
  • Related