问题
I have two react components which work independently of each other but when connected seem to break the core of my program. My setup is this: Redux store --> MusicList.js(first component) --> AppNavbar.js(second component inside MusicList.js). Independently the redux store works perfectly with the first component, but when I connect my second component to MusicList.js it breaks the importation of my store. There is also a third component "Items.js" which is connected to MusicList.js in the same fashion as the second component, it also uses the redux store as a prop and yet it works perfectly fine without breaking the program.
Here is the code:
MusicList.js:
import React, {Component, useState } from "react";
import Items from "./Items";
import AddItem from "./AddItem";
import { connect } from "react-redux";
import { getItems, deleteItem, addItem, toggleItem } from "../actions/itemActions"
import PropTypes from "prop-types";
import AppNavbar from "./AppNavbar.js";
class MusicList extends Component {
// Both componentWillMount and componentDidMount fail to get the items from my databse when the AppNavbar.js is connected.
// They both work when I comment out AppNavbar.js.
// The setTimeout changes nothing.
componentWillMount() {
console.log("test")
this.props.getItems();
const func = () => {
console.log(this.props.item)
}
setTimeout(func, 5000);
}
toggle = (id) => {
this.props.toggleItem(id)
console.log(this.props.item.items)
}
delItem = (id) => {
this.props.deleteItem(id)
}
addItem = (item, url) => {
this.props.addItem(item, url)
console.log(this.props.item.items)
}
render() {
const { items } = this.props.item
console.log(items)
return (
<div>
<div class="sticky-top">
// In this example the Appnavbar is commented out.
// The program will get the items from the backend.
{/* <AppNavbar toggle={this.toggle} items={items}/> */}
<AddItem addItem={this.addItem}/>
</div>
<Items items={items} toggle={this.toggle} delItem={this.delItem} />
</div>
)
}
}
MusicList.propTypes = {
getItems: PropTypes.func.isRequired,
deleteItem: PropTypes.func.isRequired,
addItem: PropTypes.func.isRequired,
toggleItem: PropTypes.func.isRequired,
item: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
item: state.item
})
export default connect(mapStateToProps, { getItems, deleteItem, addItem, toggleItem})(MusicList);
AppNavbar.js:
import React, { Component } from "react";
import {
Navbar,
NavbarBrand,
Nav,
Button
} from "react-bootstrap";
import './style.css';
import PropTypes from "prop-types";
class AppNavbar extends Component {
playTrack = (track_index, items, placeholderTitle, isPlaying, isShuffling) => {
console.log(items)
isPlaying = true;
// playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
// Load a new track
if (isShuffling) {
track_index = Math.floor(Math.random() * items.length)
items[track_index].this.props.toggle()
// this.props.toggle(trackIndexToID)
}
else {
items[track_index].this.props.toggle()
}
// Update details of the track
placeholderTitle = this.props.items[track_index].name;
// Move to the next track if the current finishes playing
// using the 'ended' event
// items[track_index].addEventListener("ended", nextTrack);
}
playpauseTrack = (track_index, isPlaying, items, placeholderTitle, isShuffling, playTrack, pauseTrack) => {
// Switch between playing and pausing
// depending on the current state
if (!isPlaying) playTrack(track_index, items, placeholderTitle, isPlaying, isShuffling);
else pauseTrack(track_index, items, placeholderTitle, isPlaying);
}
pauseTrack = (track_index, items, placeholderTitle, isPlaying) => {
// Pause the loaded track
isPlaying = false;
// Replace icon with the play icon
// playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';
items[track_index].this.props.toggle()
}
nextTrack = (track_index, isLooping, items, playTrack) => {
// Go back to the first track if the
// current one is the last in the track list
if (track_index < items.length - 1 && !isLooping) {
track_index += 1;
}
else if (isLooping) {
track_index = track_index
}
else track_index = 0;
// Load and play the new track
playTrack(track_index);
}
prevTrack = (track_index, isLooping, items, playTrack) => {
// Go back to the last track if the
// current one is the first in the track list
if (track_index > 0 && !isLooping) {
track_index -= 1;
}
else if (isLooping) {
track_index = track_index
}
else track_index = items.length;
// Load and play the new track
playTrack(track_index);
}
// Connect to loop track icon
loopTrack = (element, isLooping, isShuffling, loopOn, shuffleOff, LoopOff) => {
if (!isLooping) {
loopOn(element, isLooping);
shuffleOff(element, isShuffling);
}
else LoopOff(element, isLooping);
}
// Connect to shuffle track icon
shuffleTrack = (element, isLooping, isShuffling, shuffleOn, LoopOff, shuffleOff) => {
if (!isShuffling) {
shuffleOn(element, isShuffling);
LoopOff(element, isLooping);
}
else shuffleOff(element, isShuffling);
}
loopOn = (element, isLooping) => {
isLooping = true;
element.style.opacity = "1"
console.log("1" + isLooping)
}
LoopOff = (element, isLooping) => {
isLooping = false;
element.style.opacity = "0.8"
console.log("2" + isLooping)
}
shuffleOn = (element, isShuffling) => {
isShuffling = true;
element.style.opacity = "1"
console.log("3" + isShuffling)
}
shuffleOff = (element, isShuffling) => {
isShuffling = false;
element.style.opacity = "0.8"
console.log("4" + isShuffling)
}
render() {
console.log(this.props.items)
var placeholderTitle = "Who asked (Feat: Nobody)";
let track_index = 0;
let isShuffling = false;
let isLooping = false;
let isPlaying = false;
return (
<Navbar className="Navbar">
<NavbarBrand id="Logo" href="#home">
<img
alt=""
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Logo-Smaller.png')}
/>
</NavbarBrand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<ul className="navbar-nav">
<li>
<a href="#" className="Title">
Embedded Music
</a>
</li>
</ul>
</Nav>
<Nav className="mr-auto">
<div id="PlayerBox">
<ul className="navbar-nav">
<li>
<header id="Player">
Now Playing:
</header>
<header id="Player">
{placeholderTitle}
</header>
<img class="Previous transparent" id="Player"
alt=""
onClick={this.prevTrack(track_index, isLooping, this.props.items, this.playTrack())}
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Previous-smallest.png')}
/>
<img class="playpauseTrack transparent" id="Player"
alt=""
onClick={this.playpauseTrack(track_index, isPlaying, this.props.items, placeholderTitle, isShuffling, this.playTrack(), this.pauseTrack())}
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Play-smallest.png')}
/>
<img class="Next transparent" id="Player"
alt=""
onClick={this.nextTrack(track_index, isLooping, this.props.items, this.playTrack())}
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Next-smallest.png')}
/>
<img class="Loop transparent" id="Player"
alt=""
onClick={this.loopTrack(this, isLooping, isShuffling, this.loopOn(), this.shuffleOff(), this.LoopOff())}
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Loop-small.png')}
/>
<img class="Shuffle transparent" id="Player"
alt=""
onClick={this.shuffleTrack(this, isLooping, isShuffling, this.shuffleOn(), this.LoopOff(), this.shuffleOff())}
src={require('D:/Parrot/Desktop/Dev/Duplicate/Embedded_Music_Player/client/src/images/Shuffle-smallest.png')}
/>
</li>
</ul>
</div>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
}
AppNavbar.propTypes = {
toggle: PropTypes.func.isRequired,
items: PropTypes.array.isRequired
}
export default AppNavbar;
Items.js:
import React, { Component } from 'react';
import Item from "./Item";
import PropTypes from "prop-types";
class Items extends Component {
render() {
return this.props.items.map((item) => (
<div>
<Item key={item._id} item={item} toggle={this.props.toggle} delItem={this.props.delItem} isOpen={item.isOpen}/>
</div>
));
}
}
// PropTypes
Items.propTypes = {
items: PropTypes.array.isRequired
}
export default Items;
The second component is quite long but when I comment out any calls to "this.props.items" the program works and MusicList.js is capable of getting the items from the backend and logging them. If I dont comment out anything I get the error of "items is undefined" and my logs in MusicList.js show the items array as empty. My leading theory is that paradoxically the error in AppNavbar which shows items are undefined effectively seizes the entire program and MusicList never mounts, and because it never mounts it never gets the items and thus it can never give the items to AppNavbar and so the cycle repeats. I'm not sure if that makes much sense but It's the only thing I can clearly see. However there is still the question of the third component, it manages to load perfectly without error and does not seize up the program like I would expect if I follow the theory above. So I am quite confused as to what the problem is and any ideas would be greatly appreciated.
来源:https://stackoverflow.com/questions/64944530/child-component-in-react-prevents-parent-component-from-importing-redux-store