React Props 不会将信息传递到确认页面
React Props doesnt pass info to the confirmation page
我是React新手,正在用React设计一个多字段的提交表单。它有一些文本域输入框和标签输入功能。用户在字段中输入他们的信息,最后,信息必须显示在确认页面上。现在我的所有信息都显示了,除了标签(来自标签输入)。好像是什么问题?
表格 (AdditionalInfo.js)
export const TagsInput = props => {
const [Tags, setTags] = React.useState(props.Tags)
const removeTags = indexToRemove => {
setTags([...Tags.filter((_, index) => index !== indexToRemove)])
}
const addTags = event => {
if (event.target.value !== '') {
setTags([...Tags, event.target.value])
props.selectedTags([...Tags, event.target.value])
event.target.value = ''
}
}
return (
<div className='tags-input'>
<ul id='tags'>
{Tags.map((Tag, index) => (
<li key={index} className='tag'>
<span className='tag-title'>{Tag}</span>
<span
className='tag-close-icon'
onClick={() => removeTags(index)}
>
x
</span>
</li>
))}
</ul>
<input
type='text'
onKeyUp={event => event.key === 'Enter' ? addTags(event) : null}
placeholder='Press enter to add tags'
/>
</div>
)
}
export class AdditionalInfo extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render() {
const {values, handleChange} = this.props
const selectedTags = Tags => {
console.log(Tags)
}
return (
<Container className='ContainerA'>
<Row>
<Col className='ACol'>
<br />
<br />
<div>
<TagsInput selectedTags={selectedTags} Tags={['Nodejs', 'MongoDB']} onChange={handleChange('Tags')}
defaultValue={values.Tags} />
</div>
<Row>
<Col xs='6' sm='4'>
<TextField
placeholder="Country"
label="Country"
onChange={handleChange('Country')}
defaultValue={values.Country}
margin="normal"
fullWidth="true"
id="outlined-basic"
variant="outlined"
required
/>
....
<div className='buttons-container' style={{position:'relative',bottom:'20px'}}>
<button onClick={this.back} className='previous'>قبلی</button>
<button form='my-form' type='submit' onClick={this.continue} className='next'>ادامه</button>
</div>
主表格持有人
//AdditionalInfo.js is used here
class CreateJob extends Component {
state = {
step:1,
Title:'',
requirements:'',
Country:'',
Region:'',
Zipcode:'',
Benefits:'',
Company:'',
InternalCode:'',
Details:'',
Tags:[],
Address:'',
Department:'',
Salary:''
}
nextStep =() => {
const {step} = this.state
this.setState({
step: step + 1
})
}
prevStep =() => {
const {step} = this.state
this.setState({
step: step - 1
})
}
handleChange = input => e => {
this.setState({ [input]: e.target.value });
};
render () {
const { step } = this.state
const {Title,Benefits,Company,InternalCode,Detailss,Tags,Address,Department,Salary,requirements,Country,Region,Zipcode } = this.state;
const values ={Title,Benefits,Company,InternalCode,Detailss,Tags,Address,Department,Salary,requirements,Country,Region,Zipcode}
return (
<div>
........
{(()=>{
switch (step) {
case 1:
return(
<AdditionalInfo
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
)
.........
这是确认页
//it uses the main form holder component info too
export class Confirmation extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render () {
const {
values: {
Title, Benefits,
Company, InternalCode, Detailss, Department,Tags, Salary,requirements,Zipcode,
Country,Region
}
} = this.props
return (
....
<div className='content'>
<Container>
<Row>
<Col xs='6' sm='4' className='TextContent'>
<Row className='TextInside'> {Salary} : حقوق پیشنهادی</Row>
<Row> زیپ کد : {Zipcode}</Row>
<Row> کشور : {Country} </Row>
..
</Col>
<Col xs='6' sm='4' className='TextContent'>
...
<Row> تگ ها : {Tags}</Row>
抱歉,代码很长,但我不明白为什么 {Country}(例如)的信息显示在此确认页面中,但未显示我来自 TagsInput {Tags} 的标签(即使它们已正确登录到控制台)我的错误在哪里?
您的 AdditionalInfo
组件将其每个输入与 handleChange
道具相关联,该道具由 parent 传递给它。更新字段时,parent 会了解它。
您的 TagsInput
组件将标签列表存储在其 own 状态(useState 挂钩)中。它从不通知 parent 它所做的任何更改。
稍后,当您的 parent(可能未显示)调用 ConfirmationPage
时,它不知道输入的标签,但它确实知道其他信息,因为它被告知他们。
相反,跟踪 parent 中的标签列表,并将当前标签列表(以及 'addTag' 和 'removeTag' 处理程序)传递给 child。
更新
我已经编辑了您的沙盒以展示一个工作示例。请注意,我确实必须删除大量对外部文件的引用才能使其编译,因此将来您可能希望在发布沙箱之前将代码精简为您遇到的确切问题。
https://codesandbox.io/s/tagger-u8fs5
一些注意事项:
- 之前不清楚你的文件结构是如何工作的。既然我看到了,您实际上不需要移动标签的状态。让 TagsInput 跟踪它自己的状态很好。但是 仍然正确,您需要用这个值更新它的 parent。为此,我添加了一个
updateParent
函数,每当您添加或删除标签时都会调用该函数。
handleChange
函数不能用于标签,因为您已将其设置为查找 e.target.value
,在这种情况下,我们直接向其发送一个值数组,而不是具有价值的事件。我添加了一个允许这样做的 handleChangeRaw
函数。
- 当您更新标签的状态时 (add/remove) 我将新的临时数组存储在一个常量中,然后可以 也 发送到 parent.您不想直接设置它(即使用
setTags
)然后让 updateParent
函数直接引用该状态,因为它会落后一个渲染(即落后一个标签)
- 在您的摘要页面上,我在您的标签输出中添加了一个
.join(',')
;否则它只是试图从元素中创建一个字符串,这将 运行 单词放在一起。
- 我会避免将 e.target.value 的值设置为 "" 以重置输入字段。这对我来说有点倒退(你正在改变那一刻的事件)。相反,我让你的代码使用输入作为 "controlled" 输入,这意味着我们跟踪它的状态并在需要时更改它(当我们需要重置它时)。这与跟踪标签列表是分开的;这里我们只是跟踪输入框的当前值。
总而言之,缺少的步骤确实是您的 parent 组件从未意识到标签中的更改。当你有嵌套组件(parent/child 关系)时,你需要仔细上下传递信息;他们不会自动分享他们所知道的。
我是React新手,正在用React设计一个多字段的提交表单。它有一些文本域输入框和标签输入功能。用户在字段中输入他们的信息,最后,信息必须显示在确认页面上。现在我的所有信息都显示了,除了标签(来自标签输入)。好像是什么问题?
表格 (AdditionalInfo.js)
export const TagsInput = props => {
const [Tags, setTags] = React.useState(props.Tags)
const removeTags = indexToRemove => {
setTags([...Tags.filter((_, index) => index !== indexToRemove)])
}
const addTags = event => {
if (event.target.value !== '') {
setTags([...Tags, event.target.value])
props.selectedTags([...Tags, event.target.value])
event.target.value = ''
}
}
return (
<div className='tags-input'>
<ul id='tags'>
{Tags.map((Tag, index) => (
<li key={index} className='tag'>
<span className='tag-title'>{Tag}</span>
<span
className='tag-close-icon'
onClick={() => removeTags(index)}
>
x
</span>
</li>
))}
</ul>
<input
type='text'
onKeyUp={event => event.key === 'Enter' ? addTags(event) : null}
placeholder='Press enter to add tags'
/>
</div>
)
}
export class AdditionalInfo extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render() {
const {values, handleChange} = this.props
const selectedTags = Tags => {
console.log(Tags)
}
return (
<Container className='ContainerA'>
<Row>
<Col className='ACol'>
<br />
<br />
<div>
<TagsInput selectedTags={selectedTags} Tags={['Nodejs', 'MongoDB']} onChange={handleChange('Tags')}
defaultValue={values.Tags} />
</div>
<Row>
<Col xs='6' sm='4'>
<TextField
placeholder="Country"
label="Country"
onChange={handleChange('Country')}
defaultValue={values.Country}
margin="normal"
fullWidth="true"
id="outlined-basic"
variant="outlined"
required
/>
....
<div className='buttons-container' style={{position:'relative',bottom:'20px'}}>
<button onClick={this.back} className='previous'>قبلی</button>
<button form='my-form' type='submit' onClick={this.continue} className='next'>ادامه</button>
</div>
主表格持有人
//AdditionalInfo.js is used here
class CreateJob extends Component {
state = {
step:1,
Title:'',
requirements:'',
Country:'',
Region:'',
Zipcode:'',
Benefits:'',
Company:'',
InternalCode:'',
Details:'',
Tags:[],
Address:'',
Department:'',
Salary:''
}
nextStep =() => {
const {step} = this.state
this.setState({
step: step + 1
})
}
prevStep =() => {
const {step} = this.state
this.setState({
step: step - 1
})
}
handleChange = input => e => {
this.setState({ [input]: e.target.value });
};
render () {
const { step } = this.state
const {Title,Benefits,Company,InternalCode,Detailss,Tags,Address,Department,Salary,requirements,Country,Region,Zipcode } = this.state;
const values ={Title,Benefits,Company,InternalCode,Detailss,Tags,Address,Department,Salary,requirements,Country,Region,Zipcode}
return (
<div>
........
{(()=>{
switch (step) {
case 1:
return(
<AdditionalInfo
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
)
.........
这是确认页
//it uses the main form holder component info too
export class Confirmation extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render () {
const {
values: {
Title, Benefits,
Company, InternalCode, Detailss, Department,Tags, Salary,requirements,Zipcode,
Country,Region
}
} = this.props
return (
....
<div className='content'>
<Container>
<Row>
<Col xs='6' sm='4' className='TextContent'>
<Row className='TextInside'> {Salary} : حقوق پیشنهادی</Row>
<Row> زیپ کد : {Zipcode}</Row>
<Row> کشور : {Country} </Row>
..
</Col>
<Col xs='6' sm='4' className='TextContent'>
...
<Row> تگ ها : {Tags}</Row>
抱歉,代码很长,但我不明白为什么 {Country}(例如)的信息显示在此确认页面中,但未显示我来自 TagsInput {Tags} 的标签(即使它们已正确登录到控制台)我的错误在哪里?
您的 AdditionalInfo
组件将其每个输入与 handleChange
道具相关联,该道具由 parent 传递给它。更新字段时,parent 会了解它。
您的 TagsInput
组件将标签列表存储在其 own 状态(useState 挂钩)中。它从不通知 parent 它所做的任何更改。
稍后,当您的 parent(可能未显示)调用 ConfirmationPage
时,它不知道输入的标签,但它确实知道其他信息,因为它被告知他们。
相反,跟踪 parent 中的标签列表,并将当前标签列表(以及 'addTag' 和 'removeTag' 处理程序)传递给 child。
更新
我已经编辑了您的沙盒以展示一个工作示例。请注意,我确实必须删除大量对外部文件的引用才能使其编译,因此将来您可能希望在发布沙箱之前将代码精简为您遇到的确切问题。
https://codesandbox.io/s/tagger-u8fs5
一些注意事项:
- 之前不清楚你的文件结构是如何工作的。既然我看到了,您实际上不需要移动标签的状态。让 TagsInput 跟踪它自己的状态很好。但是 仍然正确,您需要用这个值更新它的 parent。为此,我添加了一个
updateParent
函数,每当您添加或删除标签时都会调用该函数。 handleChange
函数不能用于标签,因为您已将其设置为查找e.target.value
,在这种情况下,我们直接向其发送一个值数组,而不是具有价值的事件。我添加了一个允许这样做的handleChangeRaw
函数。- 当您更新标签的状态时 (add/remove) 我将新的临时数组存储在一个常量中,然后可以 也 发送到 parent.您不想直接设置它(即使用
setTags
)然后让updateParent
函数直接引用该状态,因为它会落后一个渲染(即落后一个标签) - 在您的摘要页面上,我在您的标签输出中添加了一个
.join(',')
;否则它只是试图从元素中创建一个字符串,这将 运行 单词放在一起。 - 我会避免将 e.target.value 的值设置为 "" 以重置输入字段。这对我来说有点倒退(你正在改变那一刻的事件)。相反,我让你的代码使用输入作为 "controlled" 输入,这意味着我们跟踪它的状态并在需要时更改它(当我们需要重置它时)。这与跟踪标签列表是分开的;这里我们只是跟踪输入框的当前值。
总而言之,缺少的步骤确实是您的 parent 组件从未意识到标签中的更改。当你有嵌套组件(parent/child 关系)时,你需要仔细上下传递信息;他们不会自动分享他们所知道的。