- 首页
- 前端开发
- React - 具有相同动作的多个组件 &减速机
React - 具有相同动作的多个组件 &减速机
[英] React - Multiple components with the same actions & reducers
本文介绍了React - 具有相同动作的多个组件 &减速机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我创建了一个组件,可让您在单击按钮时添加/删除其他下拉列表.我使用 Redux 来保持添加字段的状态和选中的值.
它工作正常,但如果我在页面上添加组件两次(使用相同的操作和减速器),两个下拉菜单将同时更新.
我怎样才能让它们独立工作?
index.jsx
从 'react' 导入 React从'react-redux'导入{连接}从 './form/drop-down-field' 导入 DropDownField从'uuid-v4'导入uuidV4import { saveSelect, removeSelect, saveSelectValue } from './actions.js'类组件扩展 React.Component {构造函数(道具){超级(道具);}保存数据(e){让数据 = {}数据[e.target.name] = e.target.valuethis.context.store.dispatch(添加数据(数据))}addInput = (e) =>{e.preventDefault()this.props.saveSelect({id:uuidV4()})}removeInput = (index, e) =>{e.preventDefault()this.props.removeSelect(index)}saveSelectValue = (e, id) =>{让数据 = {}数据.id = iddata.value = e.target.valuethis.props.saveSelectValue(data)}renderNationalitiesSelect = (selection, index) =>{const selectedValue = selection.value ||''const id = selection.id返回(<div><下拉字段键={id}名称={'字段-'+ id}值={selectedValue}onChange = {(e) =>{ this.saveSelectValue(e, id) }}必需的选项={{0: '请选择',1:'英国',2:'法国',3:'美国',4:'澳大利亚'}}/><a href="#" onClick={ (e) =>{this.removeInput(index, e) }}>Remove</a>
)}renderCountriesSelect = (selection, index) =>{const selectedValue = selection.value ||''const id = selection.id返回(<div><下拉字段键={id}名称={'字段-'+ id}值={selectedValue}onChange = {(e) =>{ this.saveSelectValue(e, id) }}必需的选项={{0: '请选择',1:英国",2:'法国',3:美国",4:澳大利亚"}}/><a href="#" onClick={ (e) =>{this.removeInput(index, e) }}>Remove</a>
)}使成为(){const selections = this.props.selections ||[]让 {国籍,居住国家} = this.props.store返回 (<DropDownField name="Nationality" value={Nationality} options={{0:请选择",1:英国",2:法国",3:美国",4:澳大利亚"}} onChange={this.saveData.bind(this)}/><div><div>{selections.map(this.renderNationalitiesSelect)}
{this.props.selections.length <4 &&<div><a href="#" onClick={this.addInput}>添加</a>
}
<DropDownField name="CountryOfResidence" value={CountryOfResidence} options={{0:请选择",1:英国",2:法国",3:美国",4:澳大利亚"}} onChange={this.saveData.bind(this)}/><div><div>{selections.map(this.renderCountriesSelect)}
{this.props.selections.length <4 &&<div><a href="#" onClick={this.addInput}>添加</a>
}
)}}const mapStateToProps = (状态) =>{返回 {商店:state.AddDropdown,选择:state.AddDropdown.selections,}}const AddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component)导出默认 AddDropdown
action.js
export const ADD_DATA = 'ADD_DATA'导出 const ADD_SELECT = 'ADD_SELECT'导出常量 REMOVE_SELECT = 'REMOVE_SELECT'导出 const SAVE_SELECT_OPTION = 'SAVE_SELECT_OPTION'导出函数 addData(data) {返回{类型:ADD_DATA,数据}}导出函数 saveSelect(data) {返回{类型:ADD_SELECT,数据}}导出函数 removeSelect(data) {返回 { 类型:REMOVE_SELECT,数据}}导出函数 saveSelectValue(data) {返回 { 类型:SAVE_SELECT_OPTION,数据}}
reducer.js
从'object.assign'导入ObjectAssign从redux"导入 { combineReducers }从 './actions' 导入 { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION }函数 AddDropdown(state = { selections: []}, action = {}){开关(动作.类型){案例ADD_DATA:返回 ObjectAssign({}, state, action.data)案例 ADD_SELECT:返回 {...状态,选择:[].concat(state.selections, action.data),}案例 REMOVE_SELECT:返回 {...状态,选择: state.selections.filter((selection, index) => (index !== action.data)),}案例 SAVE_SELECT_OPTION:返回 {...状态,选择: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection)}默认:返回状态}}const FormApp = combineReducers({添加下拉菜单})导出默认 FormApp
解决方案
我建议将每组下拉菜单隔离为一个单独的组件,然后努力隔离每个的 redux 状态.我的图书馆 redux-subspace 就是为此目的而设计的.
index.jsx
从 'react' 导入 React从'react-redux'导入{连接}从redux-subspace"导入 { SubspaceProvider }从 './form/drop-down-field' 导入 DropDownField从'uuid-v4'导入uuidV4import { saveSelect, removeSelect, saveSelectValue } from './actions.js'类组件扩展 React.Component {构造函数(道具){超级(道具);}保存数据(e){让数据 = {}数据[e.target.name] = e.target.valuethis.context.store.dispatch(添加数据(数据))}addInput = (e) =>{e.preventDefault()this.props.saveSelect({id:uuidV4()})}removeInput = (index, e) =>{e.preventDefault()this.props.removeSelect(index)}saveSelectValue = (e, id) =>{让数据 = {}数据.id = iddata.value = e.target.valuethis.props.saveSelectValue(data)}renderSelections = (selection, index) =>{const selectedValue = selection.value ||''const id = selection.id返回(<div><下拉字段键={id}名称={'字段-'+ id}值={selectedValue}onChange = {(e) =>{ this.saveSelectValue(e, id) }}必需的options={this.props.options}/><a href="#" onClick={ (e) =>{this.removeInput(index, e) }}>Remove</a>)}使成为(){返回 (<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)}
{this.props.selections.length <4 &&<div><a href="#" onClick={this.addInput}>添加</a>
}
)}}const mapStateToProps = (状态) =>{返回 {商店:状态,选择:state.selections,}}const SingleAddDropdown = connect(mapStateToProps, {saveSelect, removeSelect, saveSelectValue})(Component)const AddDropdown = () =>{返回 (<div><SubspaceProvider mapState={state =>state.nationality} namespace="nationalities"><SingleAddDropdown name="国籍"选项={{0: '请选择',1:'英国',2:'法国',3:'美国',4:'澳大利亚'}}/></SubspaceProvider><SubspaceProvider mapState={state =>state.countryOfResidence} namespace="countryOfResidence"><SingleAddDropdown name="居住国" options={{0: '请选择',1:英国",2:'法国',3:美国",4:澳大利亚"}}/></SubspaceProvider>
)}导出默认 AddDropdown
reducer.js
从'object.assign'导入ObjectAssign从redux"导入 { combineReducers }从'redux-subspace'导入{命名空间}从 './actions' 导入 { ADD_DATA, ADD_SELECT, REMOVE_SELECT, SAVE_SELECT_OPTION }函数 AddDropdown(state = { selections: []}, action = {}){开关(动作.类型){案例ADD_DATA:返回 ObjectAssign({}, state, action.data)案例 ADD_SELECT:返回 {...状态,选择:[].concat(state.selections, action.data),}案例 REMOVE_SELECT:返回 {...状态,选择: state.selections.filter((selection, index) => (index !== action.data)),}案例 SAVE_SELECT_OPTION:返回 {...状态,选择: state.selections.map((selection) => selection.id === action.data.id ? action.data : selection)}默认:返回状态}}const FormApp = combineReducers({命名空间(AddDropdown,国籍"),命名空间(AddDropdown,countryOfResidence")})导出默认 FormApp
注意:根据 我的评论这段代码有一些问题,我没有尝试为这个例子清理它们.
I created a component that lets you add/remove additional dropdowns onClick of a button. I use Redux to keep the state of the added fields and value selected.
It works fine but if I add the component twice on the page (using the same actions and reducers), both dropdowns will update at the same time.
How could I make them work independently?
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
解决方案
I suggest isolating each set of dropdowns as a seperate component, then working on isolating each one's redux state. My library, redux-subspace was designed for this purpose.
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
NOTE: as per my comment there are some issues with this code and I have not attempted to clean them up for this example.
这篇关于React - 具有相同动作的多个组件 &减速机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文