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

一些注意事项:

  1. 之前不清楚你的文件结构是如何工作的。既然我看到了,您实际上不需要移动标签的状态。让 TagsInput 跟踪它自己的状态很好。但是 仍然正确,您需要用这个值更新它的 parent。为此,我添加了一个 updateParent 函数,每当您添加或删除标签时都会调用该函数。
  2. handleChange 函数不能用于标签,因为您已将其设置为查找 e.target.value,在这种情况下,我们直接向其发送一个值数组,而不是具有价值的事件。我添加了一个允许这样做的 handleChangeRaw 函数。
  3. 当您更新标签的状态时 (add/remove) 我将新的临时数组存储在一个常量中,然后可以 发送到 parent.您不想直接设置它(即使用 setTags)然后让 updateParent 函数直接引用该状态,因为它会落后一个渲染(即落后一个标签)
  4. 在您的摘要页面上,我在您的标签输出中添加了一个 .join(',');否则它只是试图从元素中创建一个字符串,这将 运行 单词放在一起。
  5. 我会避免将 e.target.value 的值设置为 "" 以重置输入字段。这对我来说有点倒退(你正在改变那一刻的事件)。相反,我让你的代码使用输入作为 "controlled" 输入,这意味着我们跟踪它的状态并在需要时更改它(当我们需要重置它时)。这与跟踪标签列表是分开的;这里我们只是跟踪输入框的当前值。

总而言之,缺少的步骤确实是您的 parent 组件从未意识到标签中的更改。当你有嵌套组件(parent/child 关系)时,你需要仔细上下传递信息;他们不会自动分享他们所知道的。