useContext give error Не удается прочитать свойство '...' из неопределенного - PullRequest
0 голосов
/ 05 февраля 2020

Мне нужна помощь в этом вопросе, мой компонент приложения, как на рисунке ниже. Я хочу сохранить объект отслеживания 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;

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;

ОБНОВЛЕНИЕ: добавление компонента Tracks

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 голосов
/ 05 февраля 2020

Я думаю, что проблема здесь в том, что, поскольку selectedTrack загружается асинхронно, когда к нему обращаются из контекста, он не определен (вы можете обойти TrackContext, будучи undefined, передав значение по умолчанию в createContext вызов). Поскольку переменная selectedTrack заполняется произвольно, вы должны сохранить ее в Ref с хуком useRef и вернуть этот ref как часть значения контекста. Таким образом вы получите последнее значение 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
  }, []);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...