反应组件状态未更新

时间:2020-04-02 23:37:13

标签: javascript reactjs react-context

我无法将上下文添加到正在消耗提供程序的组件状态中。

下面的代码是一个名为Timer的子组件,父组件包装在ReadingSessionProvider中。

我将duration存储为session对象的属性,该对象存储在父级状态中。例如,它以"00:10:00"的形式存储在字符串中。我可以在父级中访问此值,而不会出现任何问题。

我想将其拆分并在状态中将分钟和小时作为单独的变量存储,以便将其用作倒数计时器,但是,如果没有某些特定事件,似乎无法访问上下文的值,在这种情况下,onClick

如果我尝试在此之前设置状态,则context.state.session.duration值是不确定的。

在下面的代码中,倒数计时器使用默认值,但是当我单击按钮时,startSession正确设置了状态,但是计时器不再起作用。例如,如果此持续时间值为"00:10:00",它将保持不变。

为此,我尝试了其他各种尝试,甚至尝试询问是否将值作为道具here传递,但没有解决方案。

我不确定我的处理方法是否有什么问题,或者我试图完成的事情是不可能的。

任何帮助将不胜感激。谢谢!

class Timer extends React.Component {
  state = {
    'minutes': 3,
    'seconds': 59,
    'timerText': 'Time Remaining: '
  }

  startCountdown() {
    this.myInterval = setInterval(() => {
      const { seconds, minutes } = this.state;

      if (seconds > 0) {
        this.setState(({ seconds }) => ({
          seconds: seconds - 1
        }))
      }

      if (seconds === 0) {
        if (minutes === 0) {
          clearInterval(this.myInterval)
        } else {
          this.setState(({ minutes }) => ({
            minutes: minutes - 1,
            seconds: 59
          }))
        }
      }

    }, 1000);
  }

  componentDidMount() {
    console.log(this.context)
    this.startCountdown();
  }

  startSession(duration) {
    this.setState({'minutes': duration.split(":")[1]});
    this.setState({'seconds': duration.split(":")[2]});
    this.startCountdown()
  }

  render() {
    return (
      <ReadingSessionContext.Consumer>
        {(context) => {
          return (
            <Typography component="h1" variant="h5">
              { this.state.minutes }:{ this.state.seconds < 10 ? `${ this.state.seconds }` : this.state.seconds }
              <Button onClick={() => this.startSession(context.state.session.duration)}>Start Session</Button>
            </Typography>
          )
        }}
      </ReadingSessionContext.Consumer>
    )
  }
}
export default function ReadingSessionPage() {  

  return (
    <ReadingSessionProvider>
      <Container component="main" maxWidth="lg">
        <NavBar />
        <CssBaseline />
        <Grid container>
          <ReadingSessionHeader />
        </Grid>
      </Container>
    </ReadingSessionProvider>
  )
}

function ReadingSessionHeader() {

  return (
    ...
      <Timer />
    ...
  )
}

和提供者(出于可读性而被截断)

export default class ReadingSessionProvider extends React.Component {

  /**
   * Set the initial state of the `ReadingSessionProvider`
   * @param {*} props 
   */
  state = {
    "translationUrl": process.env.REACT_APP_BACKEND_URL + "translate/",
    "readingSessionUrl": process.env.REACT_APP_BACKEND_URL + "reading-sessions/",
    "session": {},
    "book": {},
    "translations": [],
    "serverPage": 1,
    "clientPage": 0,
    "limit": 10,
    "totalResults": 0,
    "sessionId": 0,
    "headers": {
      "Content-type": "application/json",
      "Authorization": "Token " +  localStorage.getItem("token"),
    }
  }

  /**
   * After the component mounts, call the `getReadingSession` method
   * and update the state with response
   */
  async componentDidMount() {
    let data = await this.getReadingSession();
    this.setState({"session": data.data});
    this.setState({"book": data.data.library_item.book});
    await this.getTranslations()
  }

  ...

  render() {
    return (
      <ReadingSessionContext.Provider value={{
        state: this.state,
        getTranslations: this.getTranslations,
        submitText: this.submitText,
        handleChangePage: this.handleChangePage,
        setSessionId: this.setSessionId,
        makeUrl: this.makeUrl

      }}>
        {this.props.children}
      </ReadingSessionContext.Provider>
    )
  }
}

2 个答案:

答案 0 :(得分:0)

componentDidUpdate(prevProps, prevState, snapShot) {
If(prevState !== This.state){
this.startCountdown()
}
}

答案 1 :(得分:0)

在您的构造函数中,如果有必要,您需要将this.startSession绑定到this

因此,您需要在构造函数中包含this.startSession = this.startSession.bind(this);

constructor(props) {
  super(props);
  this.state = {put your state here};
  this.startSession = this.startSession.bind(this);
}

我认为正在发生的事情是该函数未绑定到this,所以当您说this.Anything时,它正在失去作用域,因此您的状态实际上并未被更新