Search code examples
javascriptreactjsreact-hooksreact-context

Uncaught TypeError: Cannot read property 'foreign' of undefined


I have a Context API with posts. When I go to other page, those APIs don't work. When I try to call words.length, that works. How to I reach properties of the object of words ?

Context Api :

export const WordContext = createContext();

const WordContextProvider = (props) => {
  const [words, setWords] = useState([]);

  axios.defaults.baseURL = "http://localhost:3002";

  const fetchData = async () => {
    const response = await axios.get("/words");
    if (response !== null) {
      setWords(response.data);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    <WordContext.Provider value={{ words, addWord, deleteWord, updateWord }}>
      {props.children}
    </WordContext.Provider>
  );
};

export default WordContextProvider;

App.js :

import WordContextProvider from "./contexts/WordContext";
.
.
.
<Route
          path="/quiz"
          render={() => (
            <WordContextProvider>
              <Quiz />
            </WordContextProvider>
          )}
        />

Quiz Page :

  const Quiz = () => {
  const { words } = useContext(WordContext);

  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [trueScore, setTrueScore] = useState(0);
  const [falseScore, setFalseScore] = useState(0);

  const handleAnswerClick = (e) => {
    e.preventDefault();
    const nextQuestion = currentQuestion + 1;
    setCurrentQuestion(nextQuestion);
    const counterTrue = trueScore + 1;
    setTrueScore(counterTrue);
    const counterFalse = falseScore + 1;
    setFalseScore(counterFalse);
  };

  return (
    <Form onSubmit={handleAnswerClick}>
      <Row className="justify-content-between mt-5 mb-5">
        <Col xs md={2} className="text-center">
          <FaCheckCircle
            icon="check-circle"
            className="text-success display-2"
          />
          <h1 className="mt-3">{trueScore}</h1>
        </Col>
        <Col xs md={2} className="text-center">
          <FaTimesCircle
            icon="times-circle"
            className="text-danger display-2"
          />
          <h1 className="mt-3">{falseScore}</h1>
        </Col>
      </Row>

      <Row className="d-flex justify-content-center align-items-center flex-column">
        <Col md={12} lg={6} className="text-center">
          <h2 className="fs-1 text-danger mb-5">{words[0].foreign}</h2>
        </Col>
        <Col md={12} lg={6} className="text-center">
          <h2 className="fs-1 text-danger mb-5">{words[0].native}</h2>
        </Col>
        <Button type="submit" variant="info" className="px-5 py-3 mt-5">
          Apply
        </Button>
      </Row>
    </Form>
  );
}

export default Quiz;

enter image description here


Solution

  • Because the initial value of words is an empty array. Before the api call success, value of words still is []. So words[0] will undefined and this error will appear.

    To fix, you can use optional chaining like this:

    <h2 className="fs-1 text-danger mb-5">{words[0]?.foreign}</h2>
    ...
    <h2 className="fs-1 text-danger mb-5">{words[0]?.native}</h2>