2016-11-27 48 views
0

我正在使用react和redux。在使用redux分派動作後獲取更新狀態

我有限定的容器組件作爲這樣:

import { connect } from 'react-redux'; 
import {addTag} from 'actions'; 
import ExpenseTagsControl from './expense_tags_control' 

const mapStateToProps = (state, own_props={selected_tags:[]}) => { 
    return { 
     tags_list: state.tags.tags_list 
    }; 
}; 


const mapDispatchToProps = (dispatch) => { 
    return { 
     addTag: (tag_name) => { 
      dispatch(addTag(tag_name)) 
     } 
    }; 
}; 

const AddExpenseTagsContainer = connect(
    mapStateToProps, 
    mapDispatchToProps 
)(ExpenseTagsControl); 


export default AddExpenseTagsContainer; 

的容器包裝,其被定義爲這樣一個表象成分:

// expense_tags_control.js 
import React, {Component, PropTypes} from 'react'; 
import ChipInput from 'material-ui-chip-input'; 
import Chip from 'material-ui/Chip'; 
import Avatar from 'material-ui/Avatar'; 
import Tag from 'common/svg_icons/tag'; 
import AutoComplete from 'material-ui/AutoComplete' 

import _ from 'underscore'; 



class ExpenseTagsControl extends React.Component { 

    constructor(props) { 
     super(props); 
     this.state = { 
      chips: [] 
     }; 
    }; 

    handleAdd(chip) { 

      // If the chip does not already exist, add it. the id here will be a dummy value that is not there in the tags_list 
     if (!(_.contains(_.map(this.props.tags_list, (tag) => tag.id), chip.id))) { 
      this.props.addTag(chip.name); 
     } 

      // This is wrong.  
     this.setState({ 
      chips: [...this.state.chips, chip] 
     }); 
    }; 

    handleDelete(chip) { 
     this.setState({ 
      chips: this.state.chips.filter((c) => c !== deletedChip) 
     }); 
    }; 


    chipRenderer({ text, value, isFocused, isDisabled, handleClick, handleRequestDelete }, key) { 
     const style = { 
      margin: '8px 8px 0 0', 
      float: 'left', 
      pointerEvents: isDisabled ? 'none' : undefined 
     }; 

     return (
      <Chip key={key} style={style} onTouchTap={handleClick} onRequestDelete={handleRequestDelete}> 
       <Avatar size={24} icon={<Tag />} /> 
       {text} 
      </Chip> 
     ); 
    }; 

    render() { 
     return (
      <ChipInput 
       hintText="Tags" 
       value={this.state.chips} 
       onRequestAdd={(chip) => this.handleAdd(chip)} 
       onRequestDelete={(deletedChip) => this.handleDelete(deletedChip)} 
       fullWidth={true} 
       dataSourceConfig={{ text: 'name', value: 'id' }} 
       dataSource={this.props.tags_list} 
       chipRenderer={this.chipRenderer} 
       openOnFocus={false} 
       filter={AutoComplete.fuzzyFilter} 
       onRequestDelete={console.log("Deleted")} 
      />); 
    }; 
}; 

ExpenseTagsControl.PropTypes = { 
    tags_list: PropTypes.array.isRequired, 
    addTag: PropTypes.func.isRequired, 
    value: PropTypes.array.isRequired, 
    onChange: PropTypes.func.isRequired 
}; 

export default ExpenseTagsControl; 

上面的表象部件,保持的狀態下,其指示已被選中的芯片。

ChipInput組件允許您選擇芯片,這些芯片是具有從預先存在的數據源定義的ID和名稱的對象。該組件還允許您通過輸入名稱添加新芯片。如果數據源中不存在鍵入的名稱,則會將其添加到數據源中。

我的問題

一旦addTag()動作被分派新添加芯片的ID分配。我如何獲得剛剛分派的行動結果的價值?

我想通過維護ChipInput在全局狀態中的狀態來解決此問題,並在調度addTag()操作時操縱全局狀態。但是這感覺像是太多的開銷。

+0

用戶可於ExpenseTagsControl刪除狀態,並把它在終極版。然後使用AddExpenseTagsContainer地圖將其傳回。 – DDS

回答

1

如果我的理解是正確的,你可能會想是這樣的:

class ExpenseTagsControl extends React.Component { 

    // ... 


    /* 
    * assuming your reducers are working fine and 'addTag' 
    * has updated global 'state.tags.tags_list' 
    */ 
    componentWillReceiveProps(nextProps) { 
     this.setState({ chips: this.nextProps.tags_list }); 
    } 

    // ... 
} 

注:您可能需要優化呼叫setState內基於某些條件componentWillReceiveProps以避免不必要的重新渲染。

+0

tags_list是可用的標籤列表。我將它們傳遞給此組件,以便它可以呈現自動完成。它們不是實際選定的值。對不起,我不是很清楚。 – ashwnacharya

+0

正如我所說的,我認爲'dispatch(addTag(tag_name))'正在更新'state.tags.tags_list'在某些reducer中。你可以發佈減速器代碼嗎? –

1

據我所知,OP的問題是如何派遣一個動作來修改REDX存儲並同時更新組件的本地狀態。

編輯:增加了一個工作示例

const initialState = { 
 
    tags: ['hello', 'hi', 'howdy'] 
 
} 
 

 
function reducer(state = {}, action) { 
 
    switch (action.type) { 
 
    case 'ADD_TAG': 
 
     return { 
 
     ...state, 
 
     tags: [ 
 
      ...state.tags, 
 
      action.payload.tag 
 
     ] 
 
     } 
 
    default: 
 
     return state; 
 
    } 
 
} 
 

 
const store = Redux.createStore(reducer, initialState); 
 

 
const addTag = (tag) => ({ 
 
    type: 'ADD_TAG', 
 
    payload: { 
 
    tag 
 
    } 
 
}) 
 

 
class Chips extends React.Component { 
 
    constructor(props) { 
 
     super(props); 
 
     this.chipToAdd = false; 
 
     this.state = { 
 
     chips: [] 
 
     } 
 
     this.handleAdd = this.handleAdd.bind(this); 
 
    } 
 

 
    componentWillReceiveProps(nextProps) { 
 
     console.log(this.chipToAdd); 
 
     if (this.chipToAdd) { 
 
     this.setState({ 
 
      chips: [...this.state.chips, this.chipToAdd] 
 
     }, (this.chipToAdd = false)); 
 
     } 
 
    } 
 

 
    handleAdd(chip) { 
 
     if (this.props.tags.filter(tag => tag === chip).length === 0) { 
 
     this.chipToAdd = chip; 
 
     this.props.addTag(chip); 
 
     } else { 
 
     if (this.state.chips.filter(existingChip => existingChip === chip).length === 0) { 
 
      this.setState({ 
 
      chips: [...this.state.chips, chip] 
 
      }); 
 
     } 
 
     } 
 
    } 
 

 
    render() { 
 
     return <div > 
 
      <h3> Tags added in component 's chip state</h3> 
 
\t \t \t <ul> 
 
\t \t \t \t {this.state.chips.map((chip, index) => <li key={index}>{chip}</li>)} 
 
\t \t \t </ul> 
 
\t \t \t <hr /> 
 
\t \t \t <h3>Tags in Redux Store</h3> 
 
\t \t \t {this.props.tags.map(
 
\t \t \t \t (tag, index) => <li key={index}> 
 
\t \t \t \t \t {tag} <button onClick={() => this.handleAdd(tag)}>Add</button> 
 
\t \t \t \t </li> 
 
\t \t \t)} 
 
\t \t \t <button onClick={() => this.handleAdd(' 
 
     new tag - ' + Math.floor((Math.random() * 100) + 1))}>Add a chip with new tag</button> 
 
\t \t </div> 
 
\t } 
 
} 
 

 
const mapStateToProps = ({ tags = [] }) => ({ tags }); 
 
const ConnectedChips = ReactRedux.connect(mapStateToProps, { addTag })(Chips); 
 

 
class App extends React.Component { 
 
\t render() { 
 
\t \t return <div> 
 
\t \t \t <h1>React/Redux Demo</h1> 
 
\t \t \t <ConnectedChips /> 
 
\t \t </div> 
 
\t } 
 
} 
 

 
const Provider = ReactRedux.Provider; 
 

 
ReactDOM.render(
 
    <Provider store={store}><App /></Provider>, 
 
    document.getElementById(' 
 
     root ') 
 
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<script src="https://unpkg.com/[email protected]/dist/redux.min.js"></script> 
 
<script src="https://unpkg.com/[email protected]/dist/react-redux.min.js"></script> 
 
<div id="root"></div>

+0

這不建議。此外,它不起作用。 – DDS

+0

小心闡述爲什麼不推薦?它在我測試它時起作用。 – jpdelatorre

+0

你編輯它現在它的工作原理。但它肯定是一種傳遞狀態的方式。如果點擊速度足夠快,則可能會在使用之前覆蓋chipToAdd屬性(這完全合法,因爲React不保證它會在任何特定時間調用您的方法)。此外,React調用componentWillReceiveProps甚至做任何事情的原因並不簡單或直接。它與React-Redux和你的mapStateToProps有關,當它由於任何原因而改變時,調用addTag到componentWillReceiveProps的連接可能會丟失,這意味着代碼將不會運行並且會中斷。 – DDS