【问题标题】:React/Redux - save select value onChangeReact/Redux - 保存选择值 onChange
【发布时间】:2017-06-14 16:17:34
【问题描述】:

我创建了一个组件,可让您添加/删除下拉字段(两个按钮的 onClick)。我正在使用 Redux 来保持下拉菜单的状态,这样当我来回导航(React Router)时,添加的下拉菜单不会丢失。

现在我还需要保留每个下拉菜单的值 onChange。所以 onChange 我将下拉列表的值发送到减速器,但它似乎是一次更新所有下拉列表(而不是单独更新)。

知道如何解决这个问题吗?

到目前为止,这是我的代码:

组件

import React from 'react'
import { connect } from 'react-redux'
import uuidV4 from 'uuid-v4'
import { saveSelect, removeSelect, saveSelectValue, incrementCounter, decrementCounter } from '../actions.js'


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

  addInput = (counter) => {
    this.props.saveSelect(uuidV4())
    this.props.incrementCounter(counter)
  }

  removeInput = (index, counter) => {
    this.props.removeSelect(index)
    this.props.decrementCounter(counter)
  }

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

    this.props.saveSelectValue(data)
  }

  renderSelect = (id, index) => {
    const selectedValue = this.props.selectedValue || ''
    const counter = this.props.counter

    return(
      <div className="col-12">
        <select
          key={id}
          name={'document-'+ id}
          value={selectedValue}
          onChange = {this.saveSelectValue}
        >
          <option value="0">Please Select</option>
          <option value="1">Australia</option>
          <option value="2">France</option>
          <option value="3">United Kingdom</option>
          <option value="4">United States</option>
        </select>

        <button onClick={ () => {this.removeInput(index, counter) }}>Remove</button>
      </div>
    )
  }

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

    return (
      <div>

        {this.props.counter <= 4 &&
          <button onClick={ this.addInput }>Add</button>
        }

        <div className="inputs">
          {ids.map(this.renderSelect)}
        </div>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    store: state.EligibleAbout,
    ids: state.EligibleAbout.ids,
    selectedValue: state.EligibleAbout.selectedValue,
    counter: state.EligibleAbout.counter,
  }
}

const EligibleAbout = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue, incrementCounter, decrementCounter})(AccountUpgrade)

export default EligibleAbout

action.js

export const ADD_SELECT = 'ADD_SELECT'
export const REMOVE_SELECT = 'REMOVE_SELECT'
export const SAVE_SELECT_OPTION = 'SAVE_SELECT_OPTION'
export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'
export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'

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}
}

export function incrementCounter(data) {
    return { type: INCREMENT_COUNTER, data }
}

export function decrementCounter(data) {
    return { type: DECREMENT_COUNTER, data }
}

reducer.js

import { combineReducers } from 'redux'
import { ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION } from './actions'

function EligibleAbout(state = { ids: [], counter: 0, selectedValue: 'Please select'}, action = {}){
  switch (action.type){
    case ADD_SELECT:
      return {
        ...state,
        ids: [].concat(state.ids, action.data),
      }
    case REMOVE_SELECT:
      return {
        ...state,
        ids: state.ids.filter((id, index) => (index !== action.data)),
      }
    case SAVE_SELECT_OPTION:
      return {
        ...state,
        selectedValue: action.data
      }
    case INCREMENT_COUNTER:
      return {
        ...state,
        counter: state.counter + 1
      }
    case DECREMENT_COUNTER:
      return {
        ...state,
        counter: state.counter - 1
      }
    default:
      return state
  }
}

const FormApp = combineReducers({
  EligibleAbout
})

export default FormApp

【问题讨论】:

  • but it seems to be updating all the dropdowns at once (not individually).这是什么意思?

标签: javascript reactjs redux react-router


【解决方案1】:

由于您需要保留每个 id 或下拉列表的选定值,因此最好的方法是保留一个对象数组,其中包含具有 idvalue 属性的对象,而不是字符串数组 ids。所以你必须把你的代码改成这样。我没有测试代码,所以如果你有任何问题,请在 cmets 中告诉我。

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

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

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

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

    this.props.saveSelectValue(data)
  }

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

    return(
      <div className="col-12">
        <select
          key={id}
          name={'document-'+ id}
          value={selectedValue}
          onChange = {(e) => this.saveSelectValue(e, id)}
        >
          <option value="0">Please Select</option>
          <option value="1">Australia</option>
          <option value="2">France</option>
          <option value="3">United Kingdom</option>
          <option value="4">United States</option>
        </select>

        <button onClick={ () => {this.removeInput(index) }}>Remove</button>
      </div>
    )
  }

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

    return (
      <div>
        <button onClick={ this.addInput }>Add</button>

        <div className="inputs">
          {selections.map(this.renderSelect)}
        </div>
      </div>
    )
  }
}

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

你也需要修改你的 reducer。

function EligibleAbout(state = { selections: [] } , action = {}){
  switch (action.type){
    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
  }
}

【讨论】:

  • 这是有道理的——它工作得很好。感谢您的解释和示例。
  • 我知道这与问题有关,但您如何将下拉列表限制为仅添加 5 次?
  • 您可以简单地检查selections 计数,然后再添加一个新计数。 addInput = () =&gt; { if(this.props.selections.length &lt;= 5) { this.props.saveSelect({id:uuidV4()}) }else{ //Message } }
  • 采取了一种略有不同的方法 - 如果它是一个好方法,请告诉我。我创建了一个链接到商店的计数器,并根据计数器值显示和隐藏添加按钮。我已经更新了我的代码。
  • 我不明白为什么您必须使用计数器和一组额外的状态更改来跟踪已经可用的数据。我认为您可以简单地使用元素数组的长度来做到这一点。 {this.props.ids.length &lt;= 4 &amp;&amp; &lt;button onClick={ this.addInput }&gt;Add&lt;/button&gt; }
【解决方案2】:

您只存储他们都从中读取的一个选定值。您需要为每个选择提供某种 ID,并专门保存/调用它的选定状态。比如:

   case SAVE_SELECT_OPTION:
      return {
        ...state,
        selectedValues: {
          [action.selectID]: action.data
        }
      }

当然,您需要相应地更新您的调度和操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多