2016-04-03 8 views
0

私はこれとあまりにも長い間戦ってきました。誰かが正しい方向へ向けることができますか? 問題:リストを作成すると、そのリストを更新/削除できます。私はそれにアイテムを追加し、これらのアイテムを更新/削除することもできます。別のリストを追加すると、前者のアイテムが後者に引き継がれ、アイテムを編集できなくなります。リストを削除してブラウザを更新しないと、アイテムはリストに残ります。私はリストがその項目についてのみ知っている方法で2つを結びつける方法が必要です 助けを前もって感謝します。React Reduxリストに項目を追加すると、他の作成されたリストに引き継がれます。

/actions/lists.js

export const CREATE_LIST = 'CREATE_LIST' 
export function createList(list) { 
    return { 
    type: CREATE_LIST, 
    id: uuid.v4(), 
    items: list.items || [], 
    ...list 
    } 
} 

export const CONNECT_TO_LIST = 'CONNECT_TO_LIST' 
export function connectToList(listId, itemId) { 
    return { 
    type: CONNECT_TO_LIST, 
    listId, 
    itemId 
    } 
} 

export const DISCONNECT_FROM_LIST = 'DISCONNECT_FROM_LIST' 
export function disconnectFromList(listId, itemId) { 
    return { 
    type: DISCONNECT_FROM_LIST, 
    listId, 
    itemId 
    } 
} 

/actions/items.js

export const CREATE_ITEM = 'CREATE_ITEM' 
export function createItem(item) { 
    return { 
    type: CREATE_ITEM, 
    item: { 
     id: uuid.v4(), 
     ...item 
    } 
    } 
} 

export const UPDATE_ITEM = 'UPDATE_ITEM' 
export function updateItem(updatedItem) { 
    return { 
    type: UPDATE_ITEM, 
    ...updatedItem 
    } 
} 

/reducers/lists.js

import * as types from '../actions/lists' 

const initialState = [] 

export default function lists(state = initialState, action) { 
    switch (action.type) { 
    case types.CREATE_LIST: 
     return [ 
     ...state, 
     { 
      id: action.id, 
      title: action.title, 
      items: action.items || [] 
     } 
     ] 

    case types.UPDATE_LIST: 
     return state.map((list) => { 
     if(list.id === action.id) { 
      return Object.assign({}, list, action) 
     } 

     return list 
     }) 

    case types.CONNECT_TO_LIST: 
     const listId = action.listId 
     const itemId = action.itemId 

     return state.map((list) => { 
     const index = list.items.indexOf(itemId) 

     if(index >= 0) { 
      return Object.assign({}, list, { 
      items: list.items.length > 1 ? list.items.slice(0, index).concat(
       list.items.slice(index + 1)): [] 
      }) 
     } 
     if(list.id === listId) { 
      return Object.assign({}, list, { 
      items: [...list.items, itemId] 
      }) 
     } 

     return list 
     }) 

    case types.DISCONNECT_FROM_LIST: 
     return state.map((list) => { 
     if(list.id === action.listId) { 
      return Object.assign({}, list, { 
      items: list.items.filter((id) => id !== action.itemId) 
      }) 
     } 

     return list 
     }) 

    default: 
     return state 
    } 
} 

/reducers/items.js

import * as types from '../actions/items' 

const initialState = [] 

export default function items(state = initialState, action) { 
    switch (action.type) { 
    case types.CREATE_ITEM: 
     return [ ...state, action.item ] 

    case types.UPDATE_ITEM: 
     return state.map((item) => { 
     if(item.id === action.id) { 
      return Object.assign({}, item, action) 
     } 

     return item 
     }) 

    case types.DELETE_ITEM: 
     return state.filter((item) => item.id !== action.id) 

    default: 
     return state 
    } 
} 

/components/List.jsx

import React from 'react' 
import { connect } from 'react-redux' 
import { bindActionCreators } from 'redux' 
import Items from './Items' 
import Editor from './Editor' 
import * as listActionCreators from '../actions/lists' 
import * as itemActionCreators from '../actions/items' 

export default class List extends React.Component { 
    render() { 
    const { list, updateList, ...props } = this.props 
    const listId = list.id 

    return (
     <div {...props}> 
     <div className="list-header" 
      onClick={() => props.listActions.updateList({id: listId, isEditing: true})} 
     > 
      <div className="list-add-item"> 
      <button onClick={this.addItem.bind(this, listId)}>+</button> 
      </div> 
      <Editor 
      className="list-title" 
      isEditing={list.isEditing} 
      value={list.title} 
      onEdit={title => props.listActions.updateList({id: listId, title, isEditing: false})} 
      /> 
      <div className="list-delete"> 
      <button onClick={this.deleteList.bind(this, listId)}>x</button> 
      </div> 
     </div> 
     <Items 
      items={this.listItems} 
      onValueClick={id => props.itemActions.updateItem({id, isEditing: true})} 
      onEdit={(id, text) => props.itemActions.updateItem({id, text, isEditing: false})} 
      onDelete={itemId => this.deleteItem(listId, itemId)} 
     /> 
     </div> 
    ) 
    } 

    listItems() { 
    props.list.items.map(id => state.items[ 
     state.items.findIndex(item => item.id === id) 
    ]).filter(item => item) 
    } 

    deleteList(listId, e) { 
    e.stopPropagation() 

    this.props.listActions.deleteList(listId) 
    } 

    addItem(listId, event) { 
    event.stopPropagation() 

    const item = this.props.itemActions.createItem({ 
     text: 'New Shopping Item' 
    }) 

    this.props.listActions.connectToList(listId, item.id) 
    } 

    deleteItem(listId, itemId) { 
    this.props.listActions.disconnectFromList(listId, itemId) 
    this.props.itemActions.deleteItem(itemId) 
    } 
} 

function mapStateToProps(state) { 
    return { 
    lists: state.lists, 
    items: state.items 
    } 
} 

function mapDispatchToProps(dispatch) { 
    return { 
    listActions: bindActionCreators(listActionCreators, dispatch), 
    itemActions: bindActionCreators(itemActionCreators, dispatch) 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(List) 

/components/List.jsx

import React from 'react' 
import List from './List.jsx' 

export default ({lists}) => { 
    return (
    <div className="lists">{lists.map((list) => 
     <List className="list" key={list.id} list={list} id={list.id} /> 
    )}</div> 
) 
} 

/components/Items.jsx

import React from 'react' 
import { connect } from 'react-redux' 
import Editor from './Editor' 
import Item from './Item' 

export default class Items extends React.Component { 
    render() { 
    const {items, onEdit, onDelete, onValueClick, isEditing} = this.props 

    return (
     <ul className="items">{items.map(item => 
     <Item 
      className="item" 
      key={item.id} 
      id={item.id} 
      isEditing={item.isEditing}> 
      <Editor 
      isEditing={item.isEditing} 
      value={item.text} 
      onValueClick={onValueClick.bind(null, item.id)} 
      onEdit={onEdit.bind(null, item.id)} 
      onDelete={onDelete.bind(null, item.id)} 
      /> 
     </Item> 
    )}</ul> 
    ) 
    } 
} 

export default connect(
    state => ({ 
    items: state.items 
    }) 
)(Items) 

/components/Item.jsx

import React from 'react' 

export default class Item extends React.Component { 
    render() { 
    const { id, isEditing, ...props } = this.props 

    return (
     <li {...props}>{props.children}</li> 
    ) 
    } 
} 

/コンポーネント/ App.jsx

class App extends React.Component { 
    handleClick =() => { 
    this.props.dispatch(createList({title: "New Shopping List"})) 
    } 

    render() { 
    const lists = this.props.lists 

    return (
     <div> 
     <button 
      className="add-list" 
      onClick={this.handleClick}>Add Shopping List</button> 
     <Lists lists={lists}/> 
     </div> 
    ) 
    } 
} 

export default connect(state => ({ lists: state.lists }))(App) 

答えて

0

@markeriksonのヒントは私が持っていた問題の一部でしたが、完全には解決しませんでした。私は私のmapStateToPropsこの

function mapStateToProps(state, props) { 
    return { 
    lists: state.lists, 
    listItems: props.list.items.map(id => state.items[ 
     state.items.findIndex(item => item.id === id) 
     ]).filter(item => item) 
    } 
} 

に固定し、これが問題の一部であった私のItems.jsx

1

は、これはすべての時点で単一のアレイ上で動作させることを意図していると仮定すると、この部分はかなり疑わしい:

case types.CREATE_LIST: 
    return [ 
    ...state, 
    { 
     id: action.id, 
     title: action.title, 
     items: action.items || [] 
    } 
    ] 

...stateがにがあるものは何でも既存のアレイに拡大していることあなたが戻ってくる新しい配列は、あなたが実際に望むふるまいのようには聞こえません。私の最初の推測では、新しいリストを作成するときに(おそらく)は、古いリストの内容全体とその新しい項目ではなく、1つの新しい項目を返したいと思っています。

他の不変スタイルの更新コードの中には、複雑に見えるものもあります。私は、 "配列の途中にあるものを更新する"ことは常に対処するのが容易ではないことを知っています。 this SO post on updating immutable dataを見てみるとよいでしょう。これにはいくつかのアプローチがあります。 Redux関連のライブラリをカタログするリンクレポもあります。immutable data management librariesというリストがあり、これにより作業が楽になるかもしれません。

+0

だけではアイテムのために以前の実装からの接続を削除する必要がありました。それを指摘してくれてありがとう。 – Diego

関連する問題