最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to wait for a Redux action to change state from a React component - Stack Overflow

programmeradmin4浏览0评论

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 to scrollToCurrentLine(), it's using that initial value. So I think what you need to do is use ponentWillReceiveProps() and pass the new value of prop.currentLineIndex once it has been update by setCurrentLineIndex() – 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
Add a ment  | 

3 Answers 3

Reset to default 2

One 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

发布评论

评论列表(0)

  1. 暂无评论