useContext 给出错误无法读取未定义的属性“...”

sar*_*rah 6 javascript reactjs react-router

我需要有关此问题的帮助,我的应用程序组件如下图所示。我想在单击“查看详细信息”按钮时inselectedTrack使用的状态存储跟踪对象。useState然后用它来显示轨道详细信息,而不是从 API 中再次获取来获取轨道详细信息,但是当我useContext在内部使用时,会出现此错误TypeError: Cannot read property 'selectedTrack' of undefined反应组件

import React from 'react';
import Header from './Header';
import Search from '../tracks/Search';
import Tracks from '../tracks/Tracks';
import Footer from './Footer';
import TrackContextProvider from '../../contexts/TrackContext';

const Main = () => {
  return (
    <div>
      <TrackContextProvider>
        <Header />
        <Search />
        <Tracks />
        <Footer />
      </TrackContextProvider>
    </div>
  );
};

export default Main;
Run Code Online (Sandbox Code Playgroud)

TrackContext.js

import React, { createContext, useState, useEffect } from 'react';
export const TrackContext = createContext();

const TrackContextProvider = props => {

  const [tracks, setTracks] = useState([]);
  const [selectedTrack, setSelectedTrack] = useState([{}]);

  const API_KEY = process.env.REACT_APP_MUSICXMATCH_KEY;

  useEffect(() => {
    fetch(
      `https://cors-anywhere.herokuapp.com/https://api.musixmatch.com/ws/1.1/chart.tracks.get?chart_name=top&page=1&page_size=10&country=fr&f_has_lyrics=1&apikey=${API_KEY}`
    )
      .then(response => response.json())
      .then(data => setTracks(data.message.body.track_list))
      .catch(err => console.log(err));
    // to disable the warning rule of missing dependency
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // state for heading
  const [heading, setHeading] = useState(['Top 10 Tracks']);

  return (
    <TrackContext.Provider value={{ tracks, heading, selectedTrack, setSelectedTrack }}>
      {props.children}
    </TrackContext.Provider>
  );
};

export default TrackContextProvider;
Run Code Online (Sandbox Code Playgroud)

import React, { Fragment, useContext } from 'react';
import { Link } from 'react-router-dom';
import { TrackContext } from '../../contexts/TrackContext';

const TrackDetails = () => {
  const { selectedTrack } = useContext(TrackContext);
  console.log(selectedTrack);
  return (
    <Fragment>
      <Link to="/">
        <button>Go Back</button>
      </Link>
      <div>
        {selectedTrack === undefined ? (
          <p>loading ...</p>
        ) : (
          <h3>
            {selectedTrack.track.track_name} by {selectedTrack.track.artist_name}
          </h3>
        )}
        <p>lyrics.............</p>
        <div>Album Id: </div>)
      </div>
    </Fragment>
  );
};

export default TrackDetails;
Run Code Online (Sandbox Code Playgroud)

import React, { useState, useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { TrackContext } from '../../contexts/TrackContext';

const Track = ({ trackInfo }) => {
  const { selectedTrack, setSelectedTrack } = useContext(TrackContext);

  const handleClick = e => {
    setSelectedTrack(trackInfo);
  };

  console.log(selectedTrack);

  return (
    <li>
      <div>{trackInfo.track.artist_name}</div>
      <div>Track: {trackInfo.track.track_name}</div>
      <div>Album:{trackInfo.track.album_name}</div>
      <div>Rating:{trackInfo.track.track_rating}</div>
      <Link to={{ pathname: `/trackdetails/${trackInfo.track.track_id}`, param1: selectedTrack }}>
        <button onClick={handleClick}>> View Lyric</button>
      </Link>
    </li>
  );
};

export default Track;
Run Code Online (Sandbox Code Playgroud)

更新:添加轨道组件

import React, { useContext, Fragment } from 'react';
import Track from './Track';
import { TrackContext } from '../../contexts/TrackContext';

const Tracks = () => {
  const { heading, tracks } = useContext(TrackContext);

  const tracksList = tracks.map(trackInfo => {
    return <Track trackInfo={trackInfo} key={trackInfo.track.track_id} />;
  });
  return (
    <Fragment>
      <p>{heading}</p>
      {tracks.length ? <ul>{tracksList}</ul> : <p>loading...</p>}
    </Fragment>
  );
};

export default Tracks;
Run Code Online (Sandbox Code Playgroud)

Sco*_*nce 1

我认为这里的问题是,由于selectedTrack是异步加载的,当从上下文访问它时,它是未定义的(您可以通过在调用中传递默认值来绕过TrackContext它)。由于 selectedTrack 变量是随时填充的,因此您应该将其存储在with挂钩中,并将该引用作为上下文值的一部分返回。这样您就可以从该上下文的任何消费者那里获得最新的价值。undefinedcreateContextRefuseRefselectedTrack


const selectedTracks = useRef([]);
useEffect(() => {
    fetch(
      `https://cors-anywhere.herokuapp.com/https://api.musixmatch.com/ws/1.1/chart.tracks.get?chart_name=top&page=1&page_size=10&country=fr&f_has_lyrics=1&apikey=${API_KEY}`
    )
      .then(response => response.json())
      .then(data => {
        selectedTrack.current = data.message.body.track_list;
      })
      .catch(err => console.log(err));
    // to disable the warning rule of missing dependency
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

Run Code Online (Sandbox Code Playgroud)

  • 出现“undefined”错误的原因可能是因为 TrackContext 尚未初始化。您可以在 `createContext()` 调用中设置默认值,在我上面发布的代码沙箱示例中,我使用默认的空对象创建上下文,例如 `const TrackContext = createContext({});`。我还更新了代码沙箱以显示选定的曲目。希望能帮助到你!! (2认同)