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

时间:2020-02-05 19:11:42

标签: javascript reactjs react-router

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

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;

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;

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;

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;

更新:添加轨道组件

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;

1 个答案:

答案 0 :(得分:0)

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


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
  }, []);