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);
}
}
}