使用 setState update helper 和事件目标拼接成对象数组仅适用于初始数组索引,对所有其他索引均失败
Splicing into array of objects using setState update helper and event targets only works with initial array index and fails with all others
我正在尝试构建一个应用程序,它将基于带有 onChange 处理程序的表单 select 输入设置状态。我的状态是一个对象数组,我的表单 select 输入是通过映射到另一个对象数组来创建的,以便设置各种表单属性,我将使用这些属性来确定拼接到状态数组的位置和内容。
出于某种原因,我的代码适用于第一个映射表单,但无法适用于所有其他表单。这是我的代码:
import React, { Component } from 'react'
import { draft_teams } from '../utils/draftinputs';
import { getPlayers } from '../actions/playerActions';
import { saveDraftboard } from '../actions/draftActions';
import { connect } from 'react-redux';
import {
Form,
Col,
Button,
} from 'react-bootstrap';
import PropTypes from 'prop-types';
import update from 'immutability-helper';
class DraftForm extends Component {
state = {
draftboard: [
{
1: {team:'', player: ''}
},
{
2: {team:'', player: ''}
},
{
3: {team:'', player: ''}
},
{
4: {team:'', player: ''}
}
]
}
onChange = (e) => {
e.persist();
const pickName = e.target.name
const pickValue = e.target.value
const pickObjectName = e.target.getAttribute('label')
this.setState((prevState) => update(prevState, { draftboard: [{ [pickObjectName]:
{[pickName]: {$set: pickValue}}}]} ))
}
render() {
const { players } = this.props.player;
return (
<div className='mt-5'>
<h5 className='mb-3 text-center'>Set Draft Board</h5>
<Form onSubmit={this.onSubmit}>
{draft_teams.map(( { pick, name, player }) => (
<Form.Row>
<Form.Group as={Col} sm={.5} controlId="formGridPosition">
<Form.Label>Pick #</Form.Label>
<Form.Control
defaultValue={pick}
className='mb-2'
size='sm'
name='pick'
label={pick}
as="select" >
<option>{pick}</option>
</Form.Control>
</Form.Group>
<Form.Group as={Col} controlId="formGridPosition">
<Form.Label>Team</Form.Label>
<Form.Control
onChange={this.onChange}
defaultValue={name}
label={pick}
size='sm'
className='mb-2'
name='team'
as="select">
{draft_teams.map(({ name }) => (
<option>{name}</option>
))}
</Form.Control>
</Form.Group>
<Form.Group as={Col} controlId="formGridPosition">
<Form.Label>Player - Consensus Pick {pick} - {player}</Form.Label>
<Form.Control
onChange={this.onChange}
size='sm'
defaultValue={player}
className='mb-2'
name='player'
label={pick}
as="select">
{players.map(({ name }) => (
<option>{name}</option>
))}
</Form.Control>
</Form.Group>
</Form.Row>
))}
<Button
className='mb-5'
variant="success"
type="submit"
block
>Save Draft Board
</Button>
</Form>
</div>
)
}
}
DraftForm.propTypes = {
player: PropTypes.object.isRequired,
getPlayers: PropTypes.func.isRequired
}
const mapStateToProps = state => ({
player: state.player
})
export default connect(mapStateToProps, { getPlayers })(DraftForm)
奇怪的是,它与第一种形式完美搭配,但与所有其他形式搭配时却失败了,而且我收到一条错误消息,指出 event.targets 未定义。有人知道为什么会这样吗?谢谢!
Error here
编辑:根据要求包含完整的class代码
您应该使用 $merge
而不是 $set
。
$set
替换对象
$merge
替换或添加 属性 但保留对象属性
但问题是你需要在数组中包含位置,也许你需要 draftboard
是对象而不是数组:
我会给出两种解决方案:
- 继续这个结构:
// state structure
state = {
draftboard: [
{
1: {team:'', player: ''}
},
{
2: {team:'', player: ''}
},
{
3: {team:'', player: ''}
},
{
4: {team:'', player: ''}
}
]
}
// Test it in componentDidMount and it works
componentDidMount() {
// this will change position 0 in `draftboard` and key 1 inside the object
this.setState(
prevState =>
update(prevState, {
draftboard: {
0: {
1: {
$merge: {
team: "hey"
}
}
}
}
}),
() => {
// this will change position 1 in `draftboard` and key 2 inside the object
this.setState(prevState =>
update(prevState, {
draftboard: {
1: {
2: {
$merge: {
team: "how"
}
}
}
}
})
);
}
);
}
- 更改为对象:
// state structure
state = {
draftboard: {
1: { team: "", player: "" },
2: { team: "", player: "" },
3: { team: "", player: "" }
}
};
// Test it in componentDidMount and it works
componentDidMount() {
this.setState(
prevState =>
update(prevState, {
draftboard: {
1: {
$merge: {
team: "team1"
}
}
}
}),
() => {
this.setState(prevState =>
update(prevState, {
draftboard: {
1: {
$merge: {
player: "team1"
}
}
}
})
);
}
);
}
现在,如果您想通过字符串更改第二个示例中的数字属性,最终结构
// state structure
state = {
draftboard: {
pick1: { team: "", player: "" },
pick2: { team: "", player: "" },
pick3: { team: "", player: "" }
}
};
// update structure
// We will change property player of key `pick1` in draftboard
this.setState(prevState =>
update(prevState, {
draftboard: {
['pick1']: {
$merge: {
player: "team1"
}
}
}
})
);
我正在尝试构建一个应用程序,它将基于带有 onChange 处理程序的表单 select 输入设置状态。我的状态是一个对象数组,我的表单 select 输入是通过映射到另一个对象数组来创建的,以便设置各种表单属性,我将使用这些属性来确定拼接到状态数组的位置和内容。
出于某种原因,我的代码适用于第一个映射表单,但无法适用于所有其他表单。这是我的代码:
import React, { Component } from 'react'
import { draft_teams } from '../utils/draftinputs';
import { getPlayers } from '../actions/playerActions';
import { saveDraftboard } from '../actions/draftActions';
import { connect } from 'react-redux';
import {
Form,
Col,
Button,
} from 'react-bootstrap';
import PropTypes from 'prop-types';
import update from 'immutability-helper';
class DraftForm extends Component {
state = {
draftboard: [
{
1: {team:'', player: ''}
},
{
2: {team:'', player: ''}
},
{
3: {team:'', player: ''}
},
{
4: {team:'', player: ''}
}
]
}
onChange = (e) => {
e.persist();
const pickName = e.target.name
const pickValue = e.target.value
const pickObjectName = e.target.getAttribute('label')
this.setState((prevState) => update(prevState, { draftboard: [{ [pickObjectName]:
{[pickName]: {$set: pickValue}}}]} ))
}
render() {
const { players } = this.props.player;
return (
<div className='mt-5'>
<h5 className='mb-3 text-center'>Set Draft Board</h5>
<Form onSubmit={this.onSubmit}>
{draft_teams.map(( { pick, name, player }) => (
<Form.Row>
<Form.Group as={Col} sm={.5} controlId="formGridPosition">
<Form.Label>Pick #</Form.Label>
<Form.Control
defaultValue={pick}
className='mb-2'
size='sm'
name='pick'
label={pick}
as="select" >
<option>{pick}</option>
</Form.Control>
</Form.Group>
<Form.Group as={Col} controlId="formGridPosition">
<Form.Label>Team</Form.Label>
<Form.Control
onChange={this.onChange}
defaultValue={name}
label={pick}
size='sm'
className='mb-2'
name='team'
as="select">
{draft_teams.map(({ name }) => (
<option>{name}</option>
))}
</Form.Control>
</Form.Group>
<Form.Group as={Col} controlId="formGridPosition">
<Form.Label>Player - Consensus Pick {pick} - {player}</Form.Label>
<Form.Control
onChange={this.onChange}
size='sm'
defaultValue={player}
className='mb-2'
name='player'
label={pick}
as="select">
{players.map(({ name }) => (
<option>{name}</option>
))}
</Form.Control>
</Form.Group>
</Form.Row>
))}
<Button
className='mb-5'
variant="success"
type="submit"
block
>Save Draft Board
</Button>
</Form>
</div>
)
}
}
DraftForm.propTypes = {
player: PropTypes.object.isRequired,
getPlayers: PropTypes.func.isRequired
}
const mapStateToProps = state => ({
player: state.player
})
export default connect(mapStateToProps, { getPlayers })(DraftForm)
奇怪的是,它与第一种形式完美搭配,但与所有其他形式搭配时却失败了,而且我收到一条错误消息,指出 event.targets 未定义。有人知道为什么会这样吗?谢谢! Error here
编辑:根据要求包含完整的class代码
您应该使用 $merge
而不是 $set
。
$set
替换对象
$merge
替换或添加 属性 但保留对象属性
但问题是你需要在数组中包含位置,也许你需要 draftboard
是对象而不是数组:
我会给出两种解决方案:
- 继续这个结构:
// state structure
state = {
draftboard: [
{
1: {team:'', player: ''}
},
{
2: {team:'', player: ''}
},
{
3: {team:'', player: ''}
},
{
4: {team:'', player: ''}
}
]
}
// Test it in componentDidMount and it works
componentDidMount() {
// this will change position 0 in `draftboard` and key 1 inside the object
this.setState(
prevState =>
update(prevState, {
draftboard: {
0: {
1: {
$merge: {
team: "hey"
}
}
}
}
}),
() => {
// this will change position 1 in `draftboard` and key 2 inside the object
this.setState(prevState =>
update(prevState, {
draftboard: {
1: {
2: {
$merge: {
team: "how"
}
}
}
}
})
);
}
);
}
- 更改为对象:
// state structure
state = {
draftboard: {
1: { team: "", player: "" },
2: { team: "", player: "" },
3: { team: "", player: "" }
}
};
// Test it in componentDidMount and it works
componentDidMount() {
this.setState(
prevState =>
update(prevState, {
draftboard: {
1: {
$merge: {
team: "team1"
}
}
}
}),
() => {
this.setState(prevState =>
update(prevState, {
draftboard: {
1: {
$merge: {
player: "team1"
}
}
}
})
);
}
);
}
现在,如果您想通过字符串更改第二个示例中的数字属性,最终结构
// state structure
state = {
draftboard: {
pick1: { team: "", player: "" },
pick2: { team: "", player: "" },
pick3: { team: "", player: "" }
}
};
// update structure
// We will change property player of key `pick1` in draftboard
this.setState(prevState =>
update(prevState, {
draftboard: {
['pick1']: {
$merge: {
player: "team1"
}
}
}
})
);