У меня есть компонент списка воспроизведения, который содержит список песен. OnComponentDidMount получает данные из axios и заполняет их списком в магазине с помощью действия GET_PLAYLIST.
Существует кнопка Добавить в список воспроизведения, которая вызывает действие UPDATE_PLAYLIST, которое должно добавить выбранную песню в список воспроизведения в магазине. , затем пост-вызов axios добавляет новую песню в базу данных firebase.
Компонент списка воспроизведения должен обновляться при изменении состояния, и я не могу понять, почему это не так?
MyКомпонент Playlist.js:
import React, { Component } from "react";
import { connect } from "react-redux";
import Auxilliary from "../../hoc/Auxilliary";
import PlayListItem from "../../components/PlayListItem/PlayListItem";
import classes from "./Playlist.css";
import * as actionTypes from "../../store/actions";
import axios from "../../hoc/axios-Firebase";
class Playlist extends Component {
componentDidMount() {
const searchQuery = "/playlist.json";
axios
.get(searchQuery)
.then(response => {
const playlistSongs = [];
for (let song in response.data) {
playlistSongs.push({
artistName: response.data[song].artistName,
trackName: response.data[song].track,
collectionName: response.data[song].collectionName
});
}
this.props.onGetPlaylist(playlistSongs);
})
.catch(error => {
console.log(error);
});
}
render() {
if (this.props.playlist.length > 0) {
const results = this.props.playlist.map((playlistItem, index) => {
return (
<PlayListItem
key={index}
artist={playlistItem.artistName}
track={playlistItem.trackName}
album={playlistItem.collectionName}
/>
);
});
return (
<Auxilliary>
<table className={classes.playlistTable}>
<thead>
<tr>
<th>Track</th>
<th>Album</th>
<th>Artist</th>
</tr>
</thead>
<tbody>{results}</tbody>
</table>
</Auxilliary>
);
} else {
return null;
}
}
}
const mapStateToProps = state => {
return {
playlist: state.playlist
};
};
const mapDispatchToProps = dispatch => {
return {
onGetPlaylist: value =>
dispatch({
type: actionTypes.GET_PLAYLIST,
playlist: value
})
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Playlist);
Компонент с кнопкой «Добавить в плейлист»:
import React, { Component } from "react";
import { connect } from "react-redux";
import Auxilliary from "../../hoc/Auxilliary";
import * as actionTypes from "../../store/actions";
import axios from "../../hoc/axios-Firebase";
import classes from "./SongInfo.css";
class SongInfo extends Component {
constructor(props) {
super(props);
this.addToPlaylistHandler = this.addToPlaylistHandler.bind(this);
}
addToPlaylistHandler(
track,
trackID,
artistName,
collectionName,
kind,
trackPrice
) {
const data = {
track: track,
trackID: trackID,
artistName: artistName,
collectionName: collectionName,
kind: kind,
trackPrice: trackPrice
};
this.props.onUpdatePlaylist(data);
axios
.post("/playlist.json", data)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<Auxilliary>
<table>
<thead>
<tr>
<th>Track</th>
<th>Track ID</th>
<th>Artist Name</th>
<th>Collection Name</th>
<th>Kind</th>
<th>Track Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>{this.props.track}</td>
<td>{this.props.id}</td>
<td>{this.props.artistName}</td>
<td>{this.props.collectionName}</td>
<td>{this.props.kind}</td>
<td>{this.props.trackPrice}</td>
</tr>
</tbody>
</table>
<button
className={classes.addToPlaylist}
onClick={this.addToPlaylistHandler(
this.props.track,
this.props.id,
this.props.artistName,
this.props.collectionName,
this.props.kind,
this.props.trackPrice
)}
>
Add to Playlist
</button>
</Auxilliary>
);
}
}
const mapStateToProps = state => {
return {
playlist: state.playlist
};
};
const mapDispatchToProps = dispatch => {
return {
onUpdatePlaylist: value =>
dispatch({
type: actionTypes.UPDATE_PLAYLIST,
playlistItem: value
})
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(SongInfo);
Мой редуктор:
import * as actionTypes from "./actions";
const initialState = {
searchValue: "",
finalSearchValue: "",
searchResults: [],
sliceStart: 0,
sliceEnd: 25,
nextDisabled: false,
prevDisabled: true,
searchResult: {
id: null,
artistId: null,
artistName: "",
track: "",
collectionName: "",
kind: "",
trackPrice: null
},
playlist: []
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.UPDATE_INPUT_VALUE:
return {
...state,
searchValue: action.searchValue
};
case actionTypes.SUBMIT_QUERY:
return {
...state,
finalSearchValue: action.finalSearchValue
};
case actionTypes.SET_SEARCH_RESULTS:
return {
...state,
searchResults: action.searchResults
};
case actionTypes.GET_PLAYLIST:
return {
...state,
playlist: action.playlist
};
case actionTypes.UPDATE_PLAYLIST:
const newPlaylist = state.playlist;
newPlaylist.push(action.playlistItem);
return {
...state,
playlist: newPlaylist
};
case actionTypes.SET_INFO_SEARCH_RESULT:
return {
...state,
searchResult: {
id: action.searchResult.id,
artistId: action.searchResult.artistId,
artistName: action.searchResult.artistName,
track: action.searchResult.track,
collectionName: action.searchResult.collectionName,
kind: action.searchResult.kind,
trackPrice: action.searchResult.trackPrice
}
};
case actionTypes.GET_PREV_25:
if (state.sliceStart - 25 >= 0) {
const newSliceStart = state.sliceStart - 25;
const newSliceEnd = state.sliceEnd - 25;
state.sliceStart = newSliceStart;
state.sliceEnd = newSliceEnd;
state.nextDisabled = false;
if (0 <= newSliceStart) {
state.prevDisabled = true;
}
}
return {
...state,
sliceStart: state.sliceStart,
sliceEnd: state.sliceEnd,
prevDisabled: state.prevDisabled,
nextDisabled: state.nextDisabled
};
case actionTypes.GET_NEXT_25:
if (state.sliceEnd < state.searchResults.length) {
const newSliceStart = state.sliceStart + 25;
const newSliceEnd = state.sliceEnd + 25;
state.sliceStart = newSliceStart;
state.sliceEnd = newSliceEnd;
state.prevDisabled = false;
if (state.searchResults.length === newSliceEnd) {
state.nextDisabled = true;
}
}
return {
...state,
sliceStart: state.sliceStart,
sliceEnd: state.sliceEnd,
prevDisabled: state.prevDisabled,
nextDisabled: state.nextDisabled
};
default:
return state;
}
};
export default reducer;