React - 具有相同动作和缩减器的多个组件
问题描述:
我创建了一个组件,可以让您在按钮上单击添加/删除其他下拉列表。我使用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
答
我建议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因为有一些问题与此代码,我还没有尝试对其进行清洁这个例子。
然后,你需要两个单独的状态部件为每个单独的组件... – AJC
看来你想处理可变数量的下拉,所以设置init状态为'state = {dropdowns:[]}'那么你将有下拉列表(每个都有自己的选择)。你必须改变reducer逻辑来处理多个下拉列表 – heyhugo
另一个更简单的选择是完全跳过这个reduce,并使下拉组件有状态。 (保持组件中的状态) – heyhugo