I'm in a ponent which has a prop currentLineIndex
passed by its parent container and ing from a Redux reducer.
In the same ponent's function I update currentLineIndex
with an action creator and then I want to scroll to the new currentLineIndex
. But it's not already updated, so I scroll to the same line.
I've tried using async
/ await
as you'll see but it's not working.
In my ponent:
const { currentLineIndex, setCurrentLineIndex } = props; // passed by the parent container
const handlePlaybackEnd = async () => {
const nextIndex = currentLineIndex + 1;
// await don't wait until global state / ponent props gets updated
await setCurrentLineIndex(nextLineIndex);
// so when I scroll on next line, I scroll to the same line.
scrollToCurrentLine();
};
const scrollToCurrentLine = () => {
const currentLineEl = document.getElementById(currentLineIndex);
currentLineEl.scrollIntoView({ block: 'start', behaviour: 'smooth' });
};
in actions/index.js
:
export function setCurrentLineIndex(index) {
return { type: SET_CURRENT_LINE_INDEX, payload: index };
}
in my reducer:
case SET_CURRENT_LINE_INDEX:
return {
...state,
currentLineIndex: action.payload,
};
Action and reducers are working good and my ponent state is successfully updated, but it's already too late.
I really need to rely on Redux state, not just to pass the currentLineIndex
to scrollToCurrentLine()
, that would be too easy :)
What would be the best solution to wait until my ponent state has been updated ?
I'm in a ponent which has a prop currentLineIndex
passed by its parent container and ing from a Redux reducer.
In the same ponent's function I update currentLineIndex
with an action creator and then I want to scroll to the new currentLineIndex
. But it's not already updated, so I scroll to the same line.
I've tried using async
/ await
as you'll see but it's not working.
In my ponent:
const { currentLineIndex, setCurrentLineIndex } = props; // passed by the parent container
const handlePlaybackEnd = async () => {
const nextIndex = currentLineIndex + 1;
// await don't wait until global state / ponent props gets updated
await setCurrentLineIndex(nextLineIndex);
// so when I scroll on next line, I scroll to the same line.
scrollToCurrentLine();
};
const scrollToCurrentLine = () => {
const currentLineEl = document.getElementById(currentLineIndex);
currentLineEl.scrollIntoView({ block: 'start', behaviour: 'smooth' });
};
in actions/index.js
:
export function setCurrentLineIndex(index) {
return { type: SET_CURRENT_LINE_INDEX, payload: index };
}
in my reducer:
case SET_CURRENT_LINE_INDEX:
return {
...state,
currentLineIndex: action.payload,
};
Action and reducers are working good and my ponent state is successfully updated, but it's already too late.
I really need to rely on Redux state, not just to pass the currentLineIndex
to scrollToCurrentLine()
, that would be too easy :)
What would be the best solution to wait until my ponent state has been updated ?
Share Improve this question edited Jul 11, 2019 at 18:27 adesurirey asked Nov 6, 2017 at 19:24 adesurireyadesurirey 2,6202 gold badges19 silver badges42 bronze badges 3-
Can you pass in the current line index?
scrollToCurrentLine(nextIndex)
?await
won't work for a synchronous function. – Rick Jolly Commented Nov 6, 2017 at 19:37 -
I think what's happening is since you are passing the initial
prop.currentLineIndex
toscrollToCurrentLine()
, it's using that initial value. So I think what you need to do is useponentWillReceiveProps()
and pass the new value ofprop.currentLineIndex
once it has been update bysetCurrentLineIndex()
– JJJ Commented Nov 6, 2017 at 19:45 - If your ponent is connected to the redux state, you should have nothing to do, just wait for redux to update the state and your ponent should refresh by itself. – Gabriel Bleu Commented Nov 15, 2017 at 13:59
3 Answers
Reset to default 2One solution can be to define setCurrentLineIndex
such that it receives a callback.
//assuming the parent container is a class
setCurrentLineIndex = (index, cb)=>{
//write the logic here then execute the callback
cb()
}
// Then in your child ponent, you could do something like this
setCurrentLineIndex(nextIndex, scrollToCurrentLine)
I finally solved this by making my ponent a class ponent so I could use ponentDidUpdate
ponentDidUpdate(prevProps) {
if (prevProps.currentLineIndex !== this.props.currentLineIndex) {
this.scrollToCurrentLine(this.props.currentLineIndex);
}
}
handlePlaybackEnd = () => this.props.setCurrentLineIndex(this.props.currentLineIndex + 1);
2020 UPDATE
Hooks made it a lot simpler, no need for a class ponent, just use an effect:
const scrollToCurrentLine = useCallback(() => {
const currentLineEl = document.getElementById(currentLineIndex);
currentLineEl.scrollIntoView({ block: 'start', behaviour: 'smooth' });
}, [currentLineIndex]);
useEffect(scrollToCurrentLine, [scrollToCurrentLine]);
I solved a similar problem by creating a little npm module. It allows you to subscribe to and listen for redux actions and executes the provided callback function as soon as the state change is plete. Usage is as follows. In your ponentWillMount or ponentDidMount hook:
subscribeToWatcher(this,[
{
action:"SOME_ACTION",
callback:()=>{
console.log("Callback Working");
},
onStateChange:true
},
]);
Detailed documentation can be found at this link