反应:作为道具传递的功能无法正常工作

时间:2019-08-10 20:53:12

标签: javascript reactjs

我已经在React中编写了一个CRUD全栈任务应用程序。这与nodeJS API挂钩。该应用程序应该允许用户添加任务,删除任务以及更新在完成/未完成之间切换的类。

我设法使该应用程序正常工作,但我目前正在尝试通过将其拆分为单独的组件来进行重构。

重构前的工作示例

import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import './styles/styles.scss';

class App extends React.Component {
  constructor() {
    super();
    this.handleAddTask = this.handleAddTask.bind(this);
    this.handleDeleteTask = this.handleDeleteTask.bind(this);
    this.handleToggleComplete = this.handleToggleComplete.bind(this);

    this.state = {
      tasks: []
    };
  }

  getTasks() {
    axios.get('http://localhost:3000/tasks')
      .then(response => {
        this.setState({ tasks: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleAddTask(e) {
    e.preventDefault();
    const newTaskDescription = e.target.elements.task.value.trim();

    if(newTaskDescription.length) {
      axios.post('http://localhost:3000/tasks', {
        description: newTaskDescription
      }).then(() => {
        this.getTasks();
      });

      e.target.elements.task.value = '';
    }
  }

  handleDeleteTask(e) {
    e.preventDefault();
    const taskId = e.target.getAttribute('data-id');

    axios.delete(`http://localhost:3000/tasks/${taskId}`)
      .then(() => {
        this.getTasks();
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleToggleComplete(e) {
    e.preventDefault();
    const taskId = e.target.getAttribute('data-id');
    const tasks = this.state.tasks;
    const taskIndex = tasks.findIndex(task => task._id === taskId);
    tasks[taskIndex].completed = !tasks[taskIndex].completed;

    this.setState(() => {
      return { tasks };
    }, () => {
      axios.put(`http://localhost:3000/tasks/${taskId}`, { completed: this.state.tasks[taskIndex].completed})
        .then(() => {
          this.getTasks();
        })
        .catch(function (error) {
          console.log(error);
        });
    });
  }

  componentDidMount() {
    this.getTasks();
  }

  render() {
    return (
      <div>
        <h1>Here is a list of Tasks</h1>

        <form onSubmit={this.handleAddTask}>
          <input type="text" name="task"/>
          <button>Add a task</button>
        </form>

        {this.state.tasks.length === 0 && <p>Please add a task to get started</p>}
        <ul>
          {
            this.state.tasks.map((task) => {
              return <li
                key={task._id}
                className={ task.completed ? 'completed' : '' }
              >
                {task.description}

                <form 
                  data-id={task._id} 
                  onSubmit={this.handleToggleComplete}
                >
                  <button>Toggle</button>
                </form>

                <form 
                  data-id={task._id} 
                  onSubmit={this.handleDeleteTask}
                >
                  <button>Delete</button>
                </form>
              </li>;
            })
          }
        </ul>

      </div>
    );
  }
}

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

重新分解后的示例

import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import './styles/styles.scss';

class App extends React.Component {
  constructor() {
    super();
    this.handleAddTask = this.handleAddTask.bind(this);
    this.handleDeleteTask = this.handleDeleteTask.bind(this);
    this.handleToggleComplete = this.handleToggleComplete.bind(this);

    this.state = {
      tasks: []
    };
  }

  getTasks() {
    axios.get('http://localhost:3000/tasks')
      .then(response => {
        this.setState({ tasks: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleAddTask(e) {
    e.preventDefault();
    const newTaskDescription = e.target.elements.task.value.trim();

    if(newTaskDescription.length) {
      axios.post('http://localhost:3000/tasks', {
        description: newTaskDescription
      }).then(() => {
        this.getTasks();
      });

      e.target.elements.task.value = '';
    }
  }

  handleDeleteTask(e) {
    e.preventDefault();
    const taskId = e.target.getAttribute('data-id');

    axios.delete(`http://localhost:3000/tasks/${taskId}`)
      .then(() => {
        this.getTasks();
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleToggleComplete(e) {
    e.preventDefault();
    const taskId = e.target.getAttribute('data-id');
    const tasks = this.state.tasks;
    const taskIndex = tasks.findIndex(task => task._id === taskId);
    tasks[taskIndex].completed = !tasks[taskIndex].completed;

    this.setState(() => {
      return { tasks };
    }, () => {
      axios.put(`http://localhost:3000/tasks/${taskId}`, { completed: this.state.tasks[taskIndex].completed})
        .then(() => {
          this.getTasks();
        })
        .catch(function (error) {
          console.log(error);
        });
    });
  }

  componentDidMount() {
    this.getTasks();
  }

  render() {
    return (
      <div>
        <h1>Here is a list of Tasks</h1>

        <form onSubmit={this.handleAddTask}>
          <input type="text" name="task"/>
          <button>Add a task</button>
        </form>

        {this.state.tasks.length === 0 && <p>Please add a task to get started</p>}
        <ul>
          {
            this.state.tasks.map((task) => {
              return <Task 
                id={task._id}
                key={task._id}
                className={task.completed ? 'completed' : ''}
                description={task.description}
                handleDeleteTask={this.handleDeleteTask}
                handleToggleComplete={this.handleToggleComplete}
              />;
            })
          }
        </ul>

      </div>
    );
  }
}

const Task = (props) => {
  return (
    <div>
      {props.description}
      <form
        data-id={props._id}
        onSubmit={props.handleToggleComplete}
      >
        <button>Toggle</button>
      </form>

      <form
        data-id={props._id}
        onSubmit={ props.handleDeleteTask}
      >
        <button>Delete</button>
      </form>
    </div>
  );
};

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

这是API数据的样子:

0: {completed: false, _id: "5d4eeb8c8925d7368654559d", description: "skaksjakjjsa", __v: 0}
1: {completed: true, _id: "5d4eeb968925d7368654559f", description: "abcdefghijklmnop", __v: 0}
2: {completed: true, _id: "5d4f0de930952a4064afa954", description: "akjkjskjaka", __v: 0}
3: {completed: false, _id: "5d4f10ae2faf70425804a3c4", description: "sasas", __v: 0}
4: {completed: false, _id: "5d4f10b22faf70425804a3c5", description: "ksksksksk", __v: 0}
5: {completed: false, _id: "5d4f10b62faf70425804a3c6", description: "dgdgdgdgdg", __v: 0}
6: {completed: false, _id: "5d4f12792faf70425804a3c7", description: "alallalal", __v: 0}
7: {completed: false, _id: "5d4f12822faf70425804a3c8", description: "abcdefghijklmnop", __v: 0}

问题在于,当我尝试触发这些函数时,将handleDeleteTask和handleToggleComplete函数作为道具传递下来之后,它说e.target.getAttribute('data-id')是未定义的吗?但是据我所知,我已经在组件中定义了data-id属性?

任何帮助调试的人将不胜感激!

1 个答案:

答案 0 :(得分:3)

在您的应用组件中,您将 _id 作为 id 传递。但是在Task组件中,您正在访问错误的道具。

下面是更正的代码。

Jun30 = {'File':['LB13-LP41-10-ZR.asc', 'LB13-LP41-19-ZR.asc', 'LB13-MB50-1-ZR.asc', 'LB13-MB50-18ZR.asc'],
         '49Ti/30Si16O':[0.000405567, 0.000272094, 0.000320981, 0.000153742],
         '1 se err':[2.61586E-06, 7.65216E-07, 1.32338E-06, 1.53561E-06]}
        df30 = pd.DataFrame(Jun30)
        df30.set_index('File', inplace = True)