【问题标题】:React Component State Not UpdatingReact 组件状态未更新
【发布时间】:2020-04-02 23:37:13
【问题描述】:

我在将上下文添加到使用提供程序的组件的状态时遇到问题。

下面的代码是一个名为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>
    )
  }
}

【问题讨论】:

  • 上下文提供者如何提供上下文?
  • 我已经为提供者添加了相关代码。谢谢
  • 上下文是否传递给消费者? console.log(context) 之前返回 &lt;Typography ...

标签: javascript reactjs react-context


【解决方案1】:
componentDidUpdate(prevProps, prevState, snapShot) {
If(prevState !== This.state){
this.startCountdown()
}
}

【讨论】:

    【解决方案2】:

    如果有意义,您需要在构造函数中将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 时,它正在失去作用域,因此您的状态实际上并没有被更新

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 2018-09-25
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      相关资源
      最近更新 更多