2017-06-19 138 views
1

我创建了一个组件,可以让您在按钮上单击添加/删除其他下拉列表。我使用Redux来保持所选字段和值的状态。React - 具有相同动作和缩减器的多个组件

它工作正常,但如果我在页面上添加组件两次(使用相同的动作和缩减器),两个下拉列表将同时更新。

我怎样才能让他们独立工作?

index.jsx

import React from 'react' 
import { connect } from 'react-redux' 
import DropDownField from './form/drop-down-field' 
import uuidV4 from 'uuid-v4' 
import { saveSelect, removeSelect, saveSelectValue } from './actions.js' 


class Component extends React.Component { 
    constructor(props) { 
    super(props); 
    } 

    saveData(e) { 
    let data = {} 
    data[e.target.name] = e.target.value 

    this.context.store.dispatch(
     addData(data) 
    ) 
    } 

    addInput = (e) => { 
    e.preventDefault() 
    this.props.saveSelect({id:uuidV4()}) 
    } 

    removeInput = (index, e) => { 
    e.preventDefault() 
    this.props.removeSelect(index) 
    } 

    saveSelectValue = (e, id) => { 
    let data = {} 
    data.id = id 
    data.value = e.target.value 

    this.props.saveSelectValue(data) 
    } 

    renderNationalitiesSelect = (selection, index) => { 
    const selectedValue = selection.value || '' 
    const id = selection.id 

    return(
     <div> 
     <DropDownField 
      key={id} 
      name={'field-'+ id} 
      value={selectedValue} 
      onChange = {(e) => { this.saveSelectValue(e, id) }} 
      required 
      options={{ 
      0: 'Please Select', 
      1: 'British', 
      2: 'French', 
      3: 'American', 
      4: 'Australian' 
     }} /> 

     <a href="#" onClick={ (e) => {this.removeInput(index, e) }}>Remove</a> 
     </div> 
    ) 
    } 

    renderCountriesSelect = (selection, index) => { 
    const selectedValue = selection.value || '' 
    const id = selection.id 

    return(
     <div> 
     <DropDownField 
      key={id} 
      name={'field-'+ id} 
      value={selectedValue} 
      onChange = {(e) => { this.saveSelectValue(e, id) }} 
      required 
      options={{ 
      0: 'Please Select', 
      1: 'United Kingdom', 
      2: 'France', 
      3: 'United States', 
      4: 'Australia' 
     }} /> 

     <a href="#" onClick={ (e) => {this.removeInput(index, e) }}>Remove</a> 
     </div> 
    ) 
    } 

    render(){ 
    const selections = this.props.selections || [] 

    let { 
     Nationality, 
     CountryOfResidence 
    } = this.props.store 

    return (
     <DropDownField name="Nationality" value={Nationality} options={{ 
     0: 'Please Select', 1: 'British', 2: 'French', 3: 'American', 4: 'Australian' 
     }} onChange={this.saveData.bind(this)} /> 

     <div> 
     <div> 
      {selections.map(this.renderNationalitiesSelect)} 
     </div> 

     {this.props.selections.length < 4 && 
      <div> 
      <a href="#" onClick={this.addInput}>Add</a> 
      </div> 
     } 
     </div> 


     <DropDownField name="CountryOfResidence" value={CountryOfResidence} options={{ 
     0: 'Please Select', 1: 'United Kingdom', 2: 'France', 3: 'United States', 4: 'Australia' 
     }} onChange={this.saveData.bind(this)} /> 

     <div> 
     <div> 
      {selections.map(this.renderCountriesSelect)} 
     </div> 

     {this.props.selections.length < 4 && 
      <div> 
      <a href="#" onClick={this.addInput}>Add</a> 
      </div> 
     } 
     </div> 

    ) 
    } 
} 

const mapStateToProps = (state) => { 
    return { 
    store: state.AddDropdown, 
    selections: state.AddDropdown.selections, 
    } 
} 

const AddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component) 

export default AddDropdown 

action.js

export const ADD_DATA = 'ADD_DATA' 
export const ADD_SELECT = 'ADD_SELECT' 
export const REMOVE_SELECT = 'REMOVE_SELECT' 
export const SAVE_SELECT_OPTION = 'SAVE_SELECT_OPTION' 

export function addData(data) { 
    return { type: ADD_DATA, data } 
} 

export function saveSelect(data) { 
    return { type: ADD_SELECT, data } 
} 

export function removeSelect(data) { 
    return { type: REMOVE_SELECT, data } 
} 

export function saveSelectValue(data) { 
    return { type: SAVE_SELECT_OPTION, data } 
} 

reducer.js

import ObjectAssign from 'object.assign' 
import { combineReducers } from 'redux' 
import { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION } from './actions' 

function AddDropdown(state = { selections: []}, action = {}){ 
    switch (action.type){ 
    case ADD_DATA: 
     return ObjectAssign({}, state, action.data) 
    case ADD_SELECT: 
     return { 
     ...state, 
     selections: [].concat(state.selections, action.data), 
     } 
    case REMOVE_SELECT: 
     return { 
     ...state, 
     selections: state.selections.filter((selection, index) => (index !== action.data)), 
     } 
    case SAVE_SELECT_OPTION: 
     return { 
     ...state, 
     selections: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection) 
     } 
    default: 
     return state 
    } 
} 


const FormApp = combineReducers({ 
    AddDropdown 
}) 

export default FormApp 
+1

然后,你需要两个单独的状态部件为每个单独的组件... – AJC

+0

看来你想处理可变数量的下拉,所以设置init状态为'state = {dropdowns:[]}'那么你将有下拉列表(每个都有自己的选择)。你必须改变reducer逻辑来处理多个下拉列表 – heyhugo

+0

另一个更简单的选择是完全跳过这个reduce,并使下拉组件有状态。 (保持组件中的状态) – heyhugo

回答

0

我建议isolat将每组下拉菜单作为一个独立的组件,然后分离每个组的缩略状态。我的图书馆,redux-subspace是为此目的而设计的。

index.jsx

import React from 'react' 
import { connect } from 'react-redux' 
import { SubspaceProvider } from 'redux-subspace' 
import DropDownField from './form/drop-down-field' 
import uuidV4 from 'uuid-v4' 
import { saveSelect, removeSelect, saveSelectValue } from './actions.js' 


class Component extends React.Component { 
    constructor(props) { 
    super(props); 
    } 

    saveData(e) { 
    let data = {} 
    data[e.target.name] = e.target.value 

    this.context.store.dispatch(
     addData(data) 
    ) 
    } 

    addInput = (e) => { 
    e.preventDefault() 
    this.props.saveSelect({id:uuidV4()}) 
    } 

    removeInput = (index, e) => { 
    e.preventDefault() 
    this.props.removeSelect(index) 
    } 

    saveSelectValue = (e, id) => { 
    let data = {} 
    data.id = id 
    data.value = e.target.value 

    this.props.saveSelectValue(data) 
    } 

    renderSelections = (selection, index) => { 
    const selectedValue = selection.value || '' 
    const id = selection.id 

    return(
     <div> 
     <DropDownField 
      key={id} 
      name={'field-'+ id} 
      value={selectedValue} 
      onChange = {(e) => { this.saveSelectValue(e, id) }} 
      required 
      options={this.props.options} /> 

     <a href="#" onClick={ (e) => {this.removeInput(index, e) }}>Remove</a> 
     </div> 
    ) 
    } 

    render(){ 
    return (
     <div> 
     <DropDownField name={this.props.name} value={this.props.store.value} options={this.props.options} onChange={this.saveData.bind(this)} /> 

     <div> 
      {this.props.selections.map(this.renderSelections)} 
     </div> 

     {this.props.selections.length < 4 && 
      <div> 
      <a href="#" onClick={this.addInput}>Add</a> 
      </div> 
     } 
     </div> 
    ) 
    } 
} 

const mapStateToProps = (state) => { 
    return { 
    store: state, 
    selections: state.selections, 
    } 
} 

const SingleAddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component) 

const AddDropdown =() => { 
    return (
     <div> 
      <SubspaceProvider mapState={state => state.nationality} namespace="nationalities"> 
       <SingleAddDropdown name="Nationality" options={{ 
        0: 'Please Select', 
        1: 'British', 
        2: 'French', 
        3: 'American', 
        4: 'Australian' 
       }}/> 
      </SubspaceProvider> 
      <SubspaceProvider mapState={state => state.countryOfResidence} namespace="countryOfResidence"> 
       <SingleAddDropdown name="Country of Residence" options={{ 
        0: 'Please Select', 
        1: 'United Kingdom', 
        2: 'France', 
        3: 'United States', 
        4: 'Australia' 
       }}/> 
      </SubspaceProvider> 
     </div> 
    ) 
} 

export default AddDropdown 

reducer.js

import ObjectAssign from 'object.assign' 
import { combineReducers } from 'redux' 
import { namespaced } from 'redux-subspace' 
import { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION } from './actions' 

function AddDropdown(state = { selections: []}, action = {}){ 
    switch (action.type){ 
    case ADD_DATA: 
     return ObjectAssign({}, state, action.data) 
    case ADD_SELECT: 
     return { 
     ...state, 
     selections: [].concat(state.selections, action.data), 
     } 
    case REMOVE_SELECT: 
     return { 
     ...state, 
     selections: state.selections.filter((selection, index) => (index !== action.data)), 
     } 
    case SAVE_SELECT_OPTION: 
     return { 
     ...state, 
     selections: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection) 
     } 
    default: 
     return state 
    } 
} 


const FormApp = combineReducers({ 
    namespaced(AddDropdown, "nationality"), 
    namespaced(AddDropdown, "countryOfResidence") 
}) 

export default FormApp 

注:每my comment因为有一些问题与此代码,我还没有尝试对其进行清洁这个例子。

相关问题