在 React 如何更新元素映射数组中元素的状态?

in React How to Update the State of an element in a mapped array of elements?

我在下方或沙箱中有两个数据对象和 3 个分层组件 here。数据包含一个问题列表,每个问题都在其正下方呈现了允许多个回复的输入框。但是,我不知道如何在输入特定问题的回复后正确更新正确问题的状态。

index.js

import React from 'react';
import { render } from 'react-dom';
import QA from './qa';
//parent of qa.js

const questions = [
  {id : 1,
  question: "where is the origin of chihuahua?"},
  {id : 2,
  question: "when does the great migration happen in Africa?"}
]

const answers = [
  {
    id : 1,
    id_question : 1,
    answer: "Mexico"
    },
  {
    id : 2,
    id_question : 1,
   answer: "Argentina"
  },
  {
    id : 3,
    id_question : 2,
    answer: "Apr"
    },
  {
    id : 4,
    id_question : 2,
    answer: "May"}
]

export default class App extends React.Component {
  state = {
    q : questions, 
    a : answers
    }

  handleSubmit = (val, index) => {
    alert('index',index)
    this.setState({
      ...this.state,
      a: [...this.state.a, {id_question: index, answer: val}]
    });
  }

  render() {
    console.log(this.state)
    return (
      questions.map((q, index) =>
        <QA 
          key={index} 
          question={q.question}
          onSubmit={this.handleSubmit}
          />
      )  
    )
  }
}


render(<App />, document.getElementById('root'));

qa.js

import React from 'react';
import Answer from './answer';
import  "./style.css"
//parent of answer.js

export default class QA extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: ""
    }
  }
  render() {
    const { question } = this.props
    const { text } = this.state
    return (
      <div class='qa-block'>
        <div>Question: {question}</div>
        <Answer onSubmit={this.props.onSubmit}/>
      </div>
    )
  }
}

和answer.js

import React from 'react';

const styles = {
  backgroundColor: 'lightgray',
};

export default class Answer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: ""
    }
  }
  render() {
    const { text } = this.state
    return (
      <div style={styles}>
        <h4>Answers</h4>
        <input type="text"
          value={text} 
          onInput={(e) => this.setState({ text: e.target.value })} />
        <button onClick={() => this.props.onSubmit(this.state.text)}>Send to the parent</button>
      </div>
    )
  }
}

几个新手问题:

  1. 我在哪里调用索引以便 setState 附加到 state.answer 正确的问题 ID 并将答案 ID 增加 1?
  2. 我应该将嵌套答案作为 属性 问题吗?

感谢您的帮助!

您可以简单地将 questionNo 作为 props 传递给 qa & ans 组件,然后通过回调进行检索,如下所示:

在index.js

render() {
    console.log(this.state)
    return (
      questions.map((q, index) =>
        <QA 
          questionNo={index} 
          question={q.question}
          onSubmit={this.handleSubmit}
          />
      )  
    )
  }

在qa.js

render() {
    const { question, questionNo } = this.props
    const { text } = this.state
    return (
      <div class='qa-block'>
        <div>Question: {question}</div>
        <Answer questionNo={questionNo} onSubmit={this.props.onSubmit}/>
      </div>
    )
  }

在answer.js

render() {
    const { text } = this.state
    return (
      <div style={styles}>
        <h4>Answers</h4>
        <input type="text"
          value={text} 
          onInput={(e) => this.setState({ text: e.target.value })} />
        <button onClick={() => this.props.onSubmit(this.state.text, this.props.questionNo)}>Send to the parent</button>
      </div>
    )
  }

之后您将在 index.js

中获得点击项目的索引

因此,为了确定您需要将 id_question 传递给提交按钮的问题,因此如果您有参数,那么在回调中您将能够获得它。

获得答案后,​​您可以查找对象的答案数组并更新 userTyped 答案。

  handleSubmit = (val, text) => {
    const typedAnswer = {...this.state.a.find(ans => ans.id_question === val), userTypedAnswer: text};
    this.setState({
      ...this.state,
      a: [...this.state.a, typedAnswer]
    });
  }

代码

index.js

import React from 'react';
import { render } from 'react-dom';
import QA from './qa';
//parent of qa.js

const questions = [
  {id: 1,
  question: "where is the origin of chihuahua?"},
  {id: 2,
  question: "when does the great migration happen in africa?"}
]

const answers = [
  {id_question: 1,
  answer: "Mexico"},
  {id_question: 1,
  answer: "Argentina"},
  {id_question: 2,
  answer: "Apr"},
  {id_question: 2,
  answer: "May"}
]

export default class App extends React.Component {
  state = {
    q : questions, 
    a : answers
    }

  handleSubmit = (val, text) => {
    const typedAnswer = {...this.state.a.find(ans => ans.id_question === val), userTypedAnswer: text};
    this.setState({
      ...this.state,
      a: [...this.state.a, typedAnswer]
    });
  }

  render() {
    return (
      <>{
         questions.map((q, index) =>
        <QA 
          key={index} 
          question={q}
          onSubmit={this.handleSubmit}
          />
      )  

      }
       <p>User Typed Answers and questions after submit</p>
       {
         this.state.a.map(ans => (
           ans.userTypedAnswer && <div>
            <span>{ans.id_question}</span>: <span>{ans.userTypedAnswer}</span>
           </div>
         ))
       }
      </>
    )
  }
}


render(<App />, document.getElementById('root'));

// answer.js

import React from 'react';

const styles = {
  backgroundColor: 'lightgray',
};

export default class Answer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: ""
    }
  }
  render() {
    const { text } = this.state
    const {onSubmit, qid} = this.props
    return (
      <div style={styles}>
        <h4>Answers</h4>
        <input type="text"
          value={text} 
          onInput={(e) => this.setState({ text: e.target.value })} />
        <button onClick={() => onSubmit(qid, this.state.text)}>Send to the parent</button>
      </div>
    )
  }
}

qa.js

import React from 'react';
import Answer from './answer';
import  "./style.css"
//parent of answer.js

export default class QA extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: ""
    }
  }
  render() {
    const { question: {question, id}, onSubmit } = this.props
    const { text } = this.state
    return (
      <div class='qa-block'>
        <div>Question: {question}</div>
        <Answer onSubmit={onSubmit} qid={id}/>
      </div>
    )
  }
}

Working example