gpt4 book ai didi

javascript - React - 具有相同 Action 和 reducer 的多个组件

转载 作者:行者123 更新时间:2023-12-04 16:52:11 27 4
gpt4 key购买 nike

我创建了一个组件,可让您在单击按钮时添加/删除其他下拉列表。我使用 Redux 来保持添加的字段和值的状态被选中。

它工作正常,但如果我在页面上添加组件两次(使用相同的操作和 reducer ),两个下拉菜单将同时更新。

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

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

最佳答案

我建议将每组下拉菜单隔离为一个单独的组件,然后努力隔离每个下拉菜单的 redux 状态。我的图书馆,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这段代码有一些问题,我没有尝试在这个例子中清理它们。

关于javascript - React - 具有相同 Action 和 reducer 的多个组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44640679/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com