Удерживать входные значения в локальном состоянии, но передать родителю для отправки формы - PullRequest
0 голосов
/ 07 ноября 2019

Я новичок в области React и обучения благодаря созданию простого приложения для составления расписания, которое пользователи могут заполнять, и при его отправке оно отправляет данные в список SharePoint с помощью API-интерфейса SharePoint (см. Ниже).

enter image description here

Как я хочу, чтобы это работало Инструмент создан с использованием таблицы, и каждая строка является строкой таблицы, хранящейся в дочернем компоненте. Когда пользователь нажимает кнопку «Добавить задачу», это создает новую строку таблицы, в которую он может добавить время, которое он завершил для этой отдельной задачи. Они могут добавлять столько элементов, сколько им нужно, затем, когда они нажимают кнопку «Отправить», каждая отдельная задача отправляется в список Sharepoint в виде отдельных элементов.

Моя проблема В данный моменткогда пользователь добавляет задачу, затем добавляет текст в поле ввода. Он передается в родительское состояние, в которое необходимо будет отправить данные, но это означает, что когда вы вводите текст в одну из строк, он отражается во ВСЕХ строках. Когда я сохраняю данные в локальном состоянии, невозможно передать значения в родительское состояние, поэтому все задачи можно отправить одним щелчком мыши, но сохранить уникальные значения. Я хочу знать, есть ли в любом случае значения для каждой строки, которые будут сохранены в локальном состоянии компонентов, чтобы они были уникальными, но чтобы передать значение в родительское состояние, чтобы их можно было отправлять вместе? Или как правильно с этим справляться в React?

Код Итак, у меня есть родительский компонент под названием TimesheetTool, который включает в себя пустой массив задач и основную таблицу (каждую задачу). пользователь хочет добавить к расписанию инструмент добавляется в виде строки таблицы). Затем внутри тела таблицы я сопоставил tr для извлечения строки таблицы из дочернего компонента с именем TableRow.

Родительский компонент

import * as React from 'react';
import styles from './TimesheetTool.module.scss';
import { ITimesheetToolProps } from './ITimesheetToolProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { ISpfxReactCrudState } from './ISpfxReactCrudState'; 
import { IListItem } from './IListItem';  
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
import TableRow from './TableRow';


export default class TimesheetTool extends React.Component<ITimesheetToolProps, ISpfxReactCrudState> {
  constructor(props: ITimesheetToolProps, state: ISpfxReactCrudState) {  
      super(props);  

      this.state = {
        project:'', task:'', mon:0, tues:0, wed:0, thurs:0, fri:0, sat:0, sun:0,
        status: 'Ready',  
        items: [],
        tasks: []
      };
  }

  handleProjectChange = (event) => {this.setState({project: event.target.value}); console.log('Event:', event.target.value)}
  handleTaskChange = (event) => {this.setState({task: event.target.value})};
  handleMonChange = (event) => {this.setState({mon: event.target.value})};
  handleTuesChange = (event) => {this.setState({tues: event.target.value})};
  handleWedChange = (event) => {this.setState({wed: event.target.value})};
  handleThursChange = (event) => {this.setState({thurs: event.target.value})};
  handleFriChange = (event) => {this.setState({fri: event.target.value})};
  handleSatChange = (event) => {this.setState({sat: event.target.value})};
  handleSunChange = (event) => {this.setState({sun: event.target.value})};

  handleAddTask = (task) => {
    task.preventDefault();
    const tasks = [...this.state.tasks];
    this.setState({ tasks: this.state.tasks.concat(task) });
  }

  handleDelete = (index) => () => this.setState({tasks: this.state.tasks.filter((_, i) => i !== index)})


    public render(): React.ReactElement<ITimesheetToolProps > {  
      const items: JSX.Element[] = this.state.items.map((item: IListItem, i: number): JSX.Element => {  
        return (  
          <li>{item.Title} ({item.Id}) </li>  
        );  
      });  

      return (
        <div>
          <form>
            <button onClick={this.handleAddTask} >Add a Task</button>
            <table className={styles.table}>
              <thead>
                <tr>
                  <th>Project</th>
                  <th>Task</th>
                  <th>Monday</th>
                  <th>Tuesday</th>
                  <th>Wednesday</th>
                  <th>Thursday</th>
                  <th>Friday</th>
                  <th>Saturday</th>
                  <th>Sunday</th>
                </tr>
              </thead>
              <tbody>
                {this.state.tasks.map((task, index) => 
                  <tr key={index}>
                    <TableRow
                      handleProjectChange={this.handleProjectChange}
                      handleTaskChange = {this.handleTaskChange}
                      handleMonChange = {this.handleMonChange}
                      handleTuesChange = {this.handleTuesChange}
                      handleWedChange = {this.handleWedChange}
                      handleThursChange = {this.handleThursChange}
                      handleFriChange = {this.handleFriChange}
                      handleSatChange = {this.handleSatChange}
                      handleSunChange = {this.handleSunChange}
                      project={this.state.project}
                      task={this.state.task}
                      mon={this.state.mon}
                      tues={this.state.tues}
                      wed={this.state.wed}
                      thurs={this.state.thurs}
                      fri={this.state.fri}
                      sat={this.state.sat}
                      sun={this.state.sun}
                    />
                    <td><a href="#" onClick={this.handleDelete(index)}>Delete</a></td> 
                  </tr>
                )}
              </tbody>
            </table>
            <div>
            <a href="#" onClick={() => this.createItem()}><span>Submit</span> </a>
            </div> 
          </form>

          <div>  
            {this.state.status}  
            <ul>  
              {items}
            </ul>  
          </div>  
        </div>  
      );  
    }

    private createItem(): void {  
      this.setState({  
        status: 'Creating item...',  
        items: []  
      });  

      const body: string = JSON.stringify({  
        'Title': `Submitted: ${new Date()}`,
        'Project': `${this.state.project}`,
        'Task': `${this.state.task}`,
        'Monday': `${this.state.mon}`,
        'Tuesday': `${this.state.tues}`,
        'Wednesday': `${this.state.wed}`,
        'Thursday': `${this.state.thurs}`,
        'Friday': `${this.state.fri}`,
        'Saturday': `${this.state.sat}`,
        'Sunday': `${this.state.sun}`
      });  

      this.props.spHttpClient.post(`${this.props.siteUrl}/_api/web/lists/getbytitle('${this.props.listName}')/items`,  
      SPHttpClient.configurations.v1,  
      {  
        headers: {  
          'Accept': 'application/json;odata=nometadata',  
          'Content-type': 'application/json;odata=nometadata',  
          'odata-version': ''  
        },  
        body: body  
      })  
      .then((response: SPHttpClientResponse): Promise<IListItem> => {  
        return response.json();  
      })  
      .then((item: IListItem): void => {  
        this.setState({  
          status: `Timesheet Successfully Submitted`,  
          items: []  
        });  
      }, (error: any): void => {  
        this.setState({  
          status: 'Error while submitting timesheet' + error,  
          items: []  
        });  
      });  
    }    
}

Дочерний компонент

import * as React from 'react';
import { Component, createRef } from 'react';
import { ITimesheetToolProps } from './ITimesheetToolProps';
import { ISpfxReactCrudState } from './ISpfxReactCrudState'; 

export default class TableRow extends React.Component<ITimesheetToolProps, ISpfxReactCrudState> {      

    render() {
        return (
            <React.Fragment>
                <td><input type="text" name="project" value={this.props.project} onChange={(event) => this.props.handleProjectChange(event)} /></td>
                <td><input type="textarea" name="task" value={this.props.task} onChange={(event) => this.props.handleTaskChange(event)} /></td>
                <td><input type="number" name="mon" value={this.props.mon} onChange={(event) => this.props.handleMonChange(event)} /></td>
                <td><input type="number" name="tues" value={this.props.tues} onChange={(event) => this.props.handleTuesChange(event)} /></td>
                <td><input type="number" name="wed" value={this.props.wed} onChange={(event) => this.props.handleWedChange(event)} /></td>
                <td><input type="number" name="thurs" value={this.props.thurs} onChange={(event) => this.props.handleThursChange(event)} /></td>
                <td><input type="number" name="fri" value={this.props.fri} onChange={(event) => this.props.handleFriChange(event)}/></td>
                <td><input type="number" name="sat" value={this.props.sat} onChange={(event) => this.props.handleSatChange(event)} /></td>
                <td><input type="number" name="sun" value={this.props.sun} onChange={(event) => this.props.handleSunChange(event)} /></td>
            </React.Fragment>        
        )
    }
}

Ответы [ 2 ]

0 голосов
/ 07 ноября 2019

Я думаю, вам нужно разделить задачи, чтобы родительский элемент управлял вашим списком задач, а дочерний компонент - для каждого. Что-то вроде ниже должно работать для вас.

// Parent

export default class TimesheetTool extends React.Component<ITimesheetToolProps, ISpfxReactCrudState> {
  ...
  onUpdateTask = (index, item) => {
    this.setState(prevState => ({
      task: prevState.task.map((task, i) => {
        return index === i ? item : task
      })
    })
  }
  ...
  render () {
    ...
    {this.state.tasks.map((task, index) => 
      <tr key={index}>
        <TableRow index={index} onUpdateTask={this.onUpdateTask} /> // pass down a callback
      </tr>
    )}
    ...
  }
})

// Child

export default class TableRow extends React.Component<ITimesheetToolProps, ISpfxReactCrudState> {

  constructor() {
    this.state = {
      project:'',
      task:'',
      mon:0,
      tues:0,
      ...
    };
  }

  onChange = (event) => {
    const { name, value } = event.target
    this.setState({
      [name]: value,
    }, () => {
      this.props.onUpdateTask(this.props.index, this.state) // call the parent that the task of this index has changed
    })
  }

  render() {
    return (
      <React.Fragment>
        <td><input type="text" name="project" value={this.state.project} onChange={this.onChange} /></td>
        <td><input type="textarea" name="task" value={this.state.task} onChange={this.onChange} /></td>
        <td><input type="number" name="mon" value={this.state.mon} onChange={this.onChange} /></td>
        <td><input type="number" name="tues" value={this.state.tues} onChange={this.onChange} /></td>
        ...
      </React.Fragment>        
    )
  }
}
0 голосов
/ 07 ноября 2019

Это потому что каждая ваша строка связывается с одним единственным объектом js. Ваш код необходимо изменить, как показано ниже

Это для первого ряда

value={this.props[0].sun}

Это для второго ряда

  value={this.props[1].sun}

===================>

 <tbody>
                {this.state.tasks.map((task, index) => 
                  <tr key={index}>
                    <TableRow
                      project={this.state.project}
                      task={this.state.task}
                      mon={this.state.mon}
                      tues={this.state.tues}
                      wed={this.state.wed}
                      thurs={this.state.thurs}
                      fri={this.state.fri}
                      sat={this.state.sat}
                      sun={this.state.sun}
                    />
                    <td><a href="#" onClick={this.handleDelete(index)}>Delete</a></td> 
                  </tr>
                )}
              </tbody>

в этом бите вы передаете данные в компонент tablerow, но каждая строка указывает на один объект js, который является this.state. перейти в коллекцию. это может быть task.project что-то вроде. В любом случае, каждая строка должна указывать на один уникальный объект js в вашей коллекции данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...