【问题标题】:ADD_SONG not added to PlayListADD_SONG 未添加到播放列表
【发布时间】:2018-07-05 16:20:11
【问题描述】:

在我的应用中 有一个渲染(播放)列表的组件 (我有 2 个硬编码列表) 我可以将新列表添加到列表列表中。 当您单击列表时 显示歌曲列表,列表底部是 一个按钮,当您单击它时,会显示一个带有输入(标题、艺术家、专辑)的表单。 在我修复添加列表功能之前,歌曲已添加到“活动”列表中 但现在 该动作被分派(ADD_SONG)并在(Redux)状态中显示正确的值,但它呈现与列表相同类型的元素/组件并且未附加/添加...... 我不知道在哪里看 我希望有人能发现我的错误逻辑

AddSongForm

export default class AddSongForm extends React.PureComponent {
  constructor() {
      super();

      this.state = {
        clicked: false
      };

      this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
      this.setState({
        clicked: !this.state.clicked
      })
    }

  handleChange = (event) => {
    const value = event.target.value
    const name = event.target.name
// console.log(name, value)
// console.log(this.state);
    this.setState({
      [name]: value
    })
  }

  handleSubmit = (event) => {
    event.preventDefault()
console.log(this.state);
    if (this.state.title && this.state.artist) {
      this.props.addSong({
        title: this.state.title,
        artist: this.state.artist,
        album: this.state.album
      })
    }
  }

  render() {

    return (<div>
      <button onClick={this.handleClick}><h2>New Song+</h2></button>

  {this.state.clicked ?
     <form onSubmit={this.handleSubmit}>
        <label>
          Song Title:
          <input type="text" name="title" onChange={this.handleChange} />
        </label>
        <label>
        <br/>  Artist:
          <input type="text" name="artist" onChange={this.handleChange} />
        </label>
        <label>
        <br/>  Album:
          <input type="text" name="album" onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
      : null}
    </div>)
  }

}

AddSongFormContainer

import AddSongForm from './AddSongForm'
import { connect } from 'react-redux'

class AddSongFormContainer extends React.PureComponent {
  addSong = (song) => {
    this.props.dispatch({
      type: 'ADD_SONG',
      payload: {
        id: Math.ceil(Math.random()*10000),
        ...song
      }
    })
  }

  render() {

    return <AddSongForm addSong={this.addSong} />
  }
}

export default connect(null)(AddSongFormContainer)

具有初始状态的减速器

const initState = [

  {
    id: 1,
    title: 'Play list 1',
    data: [
      {
        id: 1,
        title: 'DogHeart II',
        artist: 'The Growlers',
        album: 'Gilded Pleasures'
      }, {
        id: 2,
        title: 'Beast of No nation',
        artist: 'Fela Kuti',
        album: 'Finding Fela'
      }, {
        id: 3,
        title: 'Satellite of love',
        artist: 'Lou Reed',
        album: 'Transformer'
      }
    ]
  }, {
    id: 2,
    title: 'Play list 2',
    data: [
      {
        id: 1,
        title: 'Whatever happend to my Rock and Roll',
        artist: 'BlackRebelMoterCycleClub',
        album: 'B.R.M.C'
      }, {
        id: 2,
        title: 'U Sexy Thing',
        artist: 'Crocodiles',
        album: 'CryBaby Demon/ U Sexy Thing'
      }, {
        id: 3,
        title: 'Oh Cody',
        artist: 'NoBunny',
        album: 'Raw Romance'
      }
    ]
  }
]
const reducer = (state = initState, action = {}) => {
  switch (action.type) {

    case 'ADD_LIST':
      return [
        ...state,
        action.payload
      ]
    case 'ADD_SONG':
      return [
        ...state,
        action.payload
      ]

    default:
      return state
  }
}

export default reducer

播放列表组件映射列表中的所有歌曲

export default class PlayList extends React.Component{
  constructor() {
      super()

      this.state = {
        clicked: false
      }
      this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
      this.setState({
        clicked: !this.state.clicked
      })
      console.log(this.props.selectList.name)

    }


render(){
  // console.log(this.props);
// console.log(this.props.playLists[0].data);
  return (<div>
    <button  onClick={this.handleClick}><h1>{this.props.playLists.title}</h1></button>
{this.state.clicked ?
  <ul>
      { this.props.playLists.data.map(song =>
        <li key={song.id} onClick={() => this.props.selectSong(song.id)}>
          <b>{song.title}</b><br/>
            By:
            <br/>
            <h3><b>{song.artist}</b></h3><br/>
             Appears on:
              <b>{song.album}</b><br/><br/>
        </li>
      ) }
      <AddSongFormContainer/>
    </ul>


     : null}


  </div>)
  }
}

初始状态(数组)中所有播放列表的容器

class PlayListsContainer extends React.PureComponent {


  selectSong = (id) => {
  this.props.dispatch({
    type: 'SELECT_SONG',
    payload: id
  })
}

  selectSong(id) {
    console.log('selected song:', id)
  }
  selectList = (id) => {
    this.props.dispatch({
      type: 'SELECT_LIST',
      payload: id
    })
  }

    selectList(id) {
      console.log('selected song:', id)
    }

    render() {
        const playlistsArray = this.props.playLists
        // console.log(playlistsArray)
        return (
            playlistsArray.map((playlist) => <PlayList
                playLists={playlist}
                selectSong={this.selectSong}
                selectList={this.selectList}
                key={playlist.id}
            />)

        )
    }








}

const mapStateToProps = (state) => {
// console.log(state.playLists);
  return {
    playLists: state.playLists



  }
}

export default connect(mapStateToProps)(PlayListsContainer)

【问题讨论】:

  • “在 (Redux) 状态下显示正确的值” - 我假设您是通过 redux 开发工具看到的?如果在 Redux 中一切正常,您的问题可能出在歌曲列表的显示上。您可以发布负责显示歌曲的反应组件/容器的代码吗?
  • 添加了我映射列表中歌曲的播放列表组件和我映射列表的播放列表容器。
  • 我应该补充一点,redux 中的一切都无法正常工作它调度操作并且 ADD_SONG 出现在我的检查器中。并且在状态下我有 playLists (一个最初包含 2 个播放列表的数组)并且它被添加到该数组中(我猜是一个播放列表)但是一个播放列表的键 id、title 和 data(array) 值(title ,artist,album) 应该进入数据数组
  • 我在我的答案中添加了一个大更新,其中包含新动作和减速器的逻辑。希望对您有所帮助!

标签: reactjs redux react-redux


【解决方案1】:

您的评论描述了您的 redux 问题,以及 Redux 开发工具的屏幕截图 - 现在问题很清楚了。

当您添加歌曲时,您只是将其添加到商店的顶层,而不是实际将其添加到播放列表中。

完全可以按原样解决这个问题。在你的 reducer 中,而不是像现在这样添加歌曲,你需要将它专门添加到播放列表中。如果你需要一个代码示例,我可以提供一个。

但是,我鼓励您重构您的 redux 存储 - 并遵循拥有 normalized, flat state. 的最佳实践

这意味着,你想为你的 redux 存储有两个顶级对象。

playlists
songs

您只需引用歌曲的 ID,而不是将有关歌曲的所有数据都包含在播放列表中。

您的播放列表如下所示:

playlists { 
  1: {
  title: 'my playlist'
  songs: [1,2,3]}

歌曲可以保持不变。

每当您将歌曲添加到播放列表时,您只需添加歌曲,然后使用新歌曲 ID 更新播放列表。

您可以做的另一种做法是使用 mapDispatchToProps 而不是内联定义您的 redux 操作调度,以使您的代码更简洁。相关文档为here.

#

要按原样修复代码,我们需要做的主要事情是传递您想要添加歌曲的播放列表 ID。否则,我们怎么知道将歌曲放在哪里?

首先,在 addSongFormContainer 中更新您的操作以接受附加参数 targetPlaylist(歌曲将进入该参数)

  addSong = (song, targetPlaylist) => {
this.props.dispatch({
  type: 'ADD_SONG',
  payload: {
    playlist: targetPlaylist
    id: Math.ceil(Math.random()*10000),
    ...song
    }
  })
}

现在使用此操作需要您传递一个目标播放列表。为简洁起见,我将硬编码将歌曲添加到播放列表 1。我将把选定的播放列表向下传递给组件的练习留给你。

我清理了 handleSubmit 以使其更清晰,将歌曲也移动到它自己的变量中。

  handleSubmit = (event) => {
  event.preventDefault()
  console.log(this.state);

  if (this.state.title && this.state.artist) {

    let song = {
      title: this.state.title,
      artist: this.state.artist,
      album: this.state.album
    }
    let selectedPlayList = 1 //Fix this later :)
    this.props.addSong(song, selectedPlayList)
  }
}

现在最后一个问题是减速器。

case 'ADD_SONG':
      const index = store.getState().findIndex(playlist => playlist.id === 
        action.payload.playlist)
      console.log(index) //This should be index 0, after looking up playlist id: 1
      const updatedPlaylistSongs = this.state[index].data
      updatedPlaylistSongs.push(action.playload.song)
      return [
        ...state.slice(0, index), // All playlists before current
        {
          ...state[index], //The targeted playlist.
          ...updatedPlaylistSongs //The updated songs
        },
        ...state.slice(index + 1), //All playlists after current
    ]

我希望reducer 对你有用,尽管它可能需要一些工作——我不习惯编写处理数组的reducer。我通常有标准化的数据,这使得修改更容易。我强烈建议您尝试规范化您的 redux 存储。停止使用数组,尝试使用生成密钥的对象(使用 uuidv4 制作唯一且随机的密钥)。这使得“选择”您想要编辑/更新的内容变得更加容易。

我希望这会有所帮助!

【讨论】:

  • 谢谢,这是一个非常有帮助的答案。您能否提供一个关于如何将其添加到播放列表的代码 sn-p 专门用代码解决它-as is-
  • 因为我刚开始学习 React-Redux,所以我不确定我在 reducer(s) 中的什么地方实现了我的逻辑
  • 谢谢先生!我看到了你在减速器中所做的事情,尽管它给了我一个 TypeError: Cannot read property 'findIndex' of undefined 可能是因为我不确定我应该给 addongform 中的 selectedPlayList 什么。我已经尝试了几件事this.state.playlist // this.props.selectList .. 事情是我对所有在 react-redux 中的连接方式有点动摇 我一定会阅读规范化我的数据(和存储等)
  • 对不起,我认为这实际上是我的错。 this.state 用于访问反应容器内的状态。它需要 getState().findIndex 才能访问 reducer 内的 redux 存储。我也修复了上面示例中的代码。
  • 未定义 getState() :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
  • 2018-03-10
相关资源
最近更新 更多