首页 > 解决方案 > 无法在 React 中访问上下文值

问题描述

我正在尝试将上下文使用者中的一个组件的值作为道具传递给另一个组件,它说它是undefined.

<ReadingSessionContext.Consumer>
  {(context) => {
    console.dir(context.state.session.duration) // Value is printed here
    return (
      ...
        <Timer duration={context.state.session.duration} />
      ...
    )
  }}
</ReadingSessionContext.Consumer>

Timer组件

class Timer extends React.Component {
  state = {
    "minutes": this.props.duration.split(":")[1].parseInt(), // Returns error here
    "seconds": this.props.duration.split(":")[2].parseInt()  // Returns error here
  }

  componentDidMount() {
    console.dir(this.props) // Value is undefined here
    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)
  }

  render() {
    const { minutes, seconds } = this.state;

    return (
      <Typography component="h1" variant="h5">
        Time Remaining: { minutes }:{ seconds < 10 ? `0${ seconds }` : seconds }
      </Typography>
    )
  }
}

我还尝试重构它,以便Timer组件使用上下文,而不是将其作为道具传递:

function Timer() {
  const context = useContext(ReadingSessionContext);
  const [minutes, setMinutes] = useState(3);
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    let duration = context.state.session.duration; // Value is accessable here
    console.log(duration); // This logs to the console correctly, and it is a string
    setMinutes(duration.split(":")[1].parseInt()); // Throws error here
    setSeconds(duration.split(":")[2].parseInt()); // Throws error here

    let timerInterval = setInterval(() => {
      if (seconds > 0) {
        setSeconds(seconds - 1);
      }

      if (seconds === 0) {
        if (minutes === 0) {
          clearInterval(this.timerInterval)
        } else {
          setMinutes(minutes - 1);
          setSeconds(59)
        }
      }
    }, 1000);
  });
}

在每种情况下,抛出的错误是 -Uncaught TypeError: Cannot read property 'split' of undefined

但是,在我调用.split()它之前检查值的每个实例中,都会告诉我该值存在,并且实际上是正确的,但是一旦我尝试对字符串执行某些操作,就会突然停止存在

提供者.jsx

import React from "react";
import axios from "axios";
import ReadingSessionContext from "./Context";

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

  /**
   * Call the API and get data for this specific reading session
   */
  async getReadingSession() {
    let result = await axios.get(
      this.state.readingSessionUrl + window.location.href.split('/')[5] + "/",
      {headers: this.state.headers}
    );
    return result;
  }

  makeUrl = sessionId => {
    return `${this.state.translationUrl}?page=${this.state.serverPage}&limit=${this.state.limit}&sessionId=${this.state.session.id}`;
  }

  /**
   * Make the API call to the server to retrieve a list of the translations
   * for the currently logged in user.
   */
  getTranslations = async () => {
    try {
      let url = `${this.state.translationUrl}?page=${this.state.serverPage}&limit=${this.state.limit}&sessionId=${this.state.session.id}`
      let response = await axios.get(url, {headers: this.state.headers});
      await this.setState({"translations": response.data.results});
      await this.setState({"totalResults": response.data.count});
    } catch (error) {
      console.log(error);
    }
  }

  /**
   * Submit the text that the user has input and get the updated 
   * list of translations from the API
   */
  submitText = async (e, text) => {
    console.log("hello?")
    let data = {
      "text_to_be_translated": text,
      "session": this.state.session.id
    };

    try {
      await axios.post(this.state.translationUrl, data, {headers: this.state.headers});
      let paginationUrl = `${this.state.translationUrl}?page=${this.state.serverPage}&limit=${this.state.limit}&sessionId=${this.state.session.id}`;
      this.getTranslations(paginationUrl);
    } catch (error) {
      console.dir(error);
    }
  }

  setSessionId = sessionId => {
    this.setState({"sessionId": sessionId});
    console.log("called")
  }

  handleChangePage = async (event, newPage) => {
    this.setState({"serverPage": newPage + 1})
    this.setState({"clientPage": newPage})
    let url = await `${this.state.translationUrl}translate/?page=${newPage + 1}&limit=${this.state.limit}&sessionId=${this.state.session.id}`
    console.log(url)
    await this.getTranslations(url);
  }

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

上下文.jsx

import React from "react";

const ReadingSessionContext = React.createContext();

export default ReadingSessionContext;

标签: javascriptreactjs

解决方案


好的。你真的很亲近。您仍然需要使用 ReadingSessionProvider 包装您的根组件或层次结构。所以这就是它通常的工作方式。

  1. 您创建上下文const ReadingSessionContext = React.createContext();
  2. 您可以使用它来创建上下文提供程序。您在创建课程时所做的ReadingSessionProvider
  3. 您使用ReadingSessionProvider包装您想要访问消费者的应用程序部分。所以说
<ReadingSessionProvider>
  <App />
</ReadingSessionProvider>
  1. 现在 App 组件的子组件可以使用 ReadingSessionProvider 中设置的值。有useContext(ReadingSessionContext)或有ReadingSessionContext.Consumer

有关更多信息,请参阅 Wes Bos 的此视频:https ://youtu.be/XLJN4JfniH4


推荐阅读