1

因此,我正在尝试与 rails 一起学习 react(将 rails 纯粹用作 API)。我正在制作一个简单的待办事项应用程序,并在尝试“创建”列表时卡住了。

我在这里显示了一个“新列表”组件,主要取自反应表单教程:

import React, { Component } from 'react';
import axios from 'axios';

class ListForm extends Component {
    constructor(props) {
      super(props);
      this.state = {
        title: '',
        description: ''
      };
      this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(e) {
      this.setState({[e.target.name]: e.target.value});
    }

    handleSubmit(e) {
      console.log("Form submitted with: " + this.state.value)
      e.preventDefault();
    }

    render() {
      return (
        <form onSubmit={this.handleSubmit}>
          <label>
            Title:
            <input name="title" type="text" value={this.state.value} onChange={this.handleInputChange} />
          </label>
          <label>
            Description:
            <textarea name="description" value={this.state.value} onChange={this.handleInputChange} />
          </label>
          <input type="submit" value="Submit" />
        </form>
      );
    }
  }

  export default ListForm;

我在这里显示了我的 ListContainer

import React, { Component } from 'react';
import axios from 'axios';
import List from './List';
import ListForm from './ListForm'

class ListContainer extends Component {
    constructor(props){
        super(props)
        this.state = {
            lists: []
        }

        this.addNewList = this.addNewList.bind(this)
    }


    componentDidMount() {
        axios.get('/api/v1/lists.json')
        .then(response => {
            console.log(response)
            this.setState({
                lists: response.data
            })
        })
        .catch(error => console.log(error))
    }

    addNewList(title, description) {
        axios.post('/api/v1/lists.json', {
            title: title,
            description: description
          })
          .then(function (response) {
            console.log(response);
            const lists = [ ...this.state.lists, response.data ]
            console.log(...this.state.lists)
            this.setState({lists})
          })
          .catch(function (error) {
            console.log(error);
          });
    }

    render() {
        return (
            <div className="lists-container">
                {this.state.lists.map( list => {
                    return (<List list={list} key={list.id} />)
                })}
                <ListForm onSubmit={this.addNewList} />
            </div>
        )
    }
}

export default ListContainer;

我的问题来自对提交回调的误解。我知道当我在表单上执行“onSubmit”时,它使用 addNewList 函数作为回调......但我真的不明白 ListForm 中状态的连接是如何进入该回调函数的。我显然做错了什么,因为它不起作用,并且当前控制台显示“提交的表单:未定义”,所以它根本没有正确传递参数。

我对 React 还是很陌生,并且对 JS 非常生疏(自从我使用它以来已经有一段时间了,所以我确定这里有一些新手错误)。此外 axios 基本上是一个“更好”的获取 fwiw。

我也不会撒谎,例如,我不完全理解我们为什么这样做this.handleSubmit = this.handleSubmit.bind(this);(以及其他类似的)

4

3 回答 3

1

我想你也有错别字。对于您拥有的更改事件

<input name="title" type="text" value={this.state.value} onChange={this.handleInputChange} />

所以更改的回调是this.handleInputChange. 但是在您的代码中,它被称为handleChange

但是即使你使用了正确的命名,它也不会起作用,因为你也需要绑定那个函数。

这让我想到了你的问题this.handleSubmit = this.handleSubmit.bind(this);

这里的问题是,当您将函数作为回调传递时,它会丢失其上下文。考虑以下

const x = { 
  log: function() { console.log(this.val) },
  val: 10
}

现在你可以做

x.log(); // -> print 10

但是当你这样做时

y = x.log;
y(); // -> prints undefined

如果你只传递它周围的函数就会失去它的上下文。要解决此问题,您可以bind

x.log = x.log.bind(x);
y = x.log
y(); // -> prints 10

希望这是有道理的:)

无论如何,回到你的问题,你不必使用绑定,有更好的方法

class ListForm extends Component {
constructor(props) {
  super(props);
  this.state = {
    title: '',
    description: ''
  };
}

handleChange = (e) => {
  this.setState({[e.target.name]: e.target.value});
}

handleSubmit = (e) => {
  console.log("Form submitted with: " + this.state.value)
  e.preventDefault();
}

虽然没有测试,但它现在可能工作!

于 2019-10-09T06:45:43.820 回答
1

你这么近!我们只需要做一些调整。

首先让我们去掉绑定语句,只使用箭头函数。箭头函数没有this对象,因此如果您this在该函数内部调用,您实际上将访问this您的类实例的对象。整洁的。

其次,让我们修正一下您的 handleChange 函数的错字,以便您的输入正确更新组件状态。

现在,真正解决您的问题。您需要在您的父组件 ListContainer 中调用 addNewList 函数。我们如何做到这一点?让我们将它作为道具传递给子组件!你快到了,但不要使用关键字onSubmit={this.addNewList},而是使用类似的东西handleSubmit。这是因为 onSubmit 实际上是一个特殊的关键字,它将一个事件监听器附加到子组件以进行提交,我们不希望这样。

现在您的子组件正在将您的功能作为道具。我们可以在 handleSubmit 函数中调用它。然后我们传入参数、标题和描述。现在您的子组件可以调用父组件中的 addNewList 函数了!

import React, { Component } from 'react';
import axios from 'axios';
import List from './List';
import ListForm from './ListForm'

class ListContainer extends Component {
    constructor(props) {
        super(props)
        this.state = {
            lists: []
        }

        this.addNewList = this.addNewList.bind(this)
    }


    componentDidMount() {
        axios.get('/api/v1/lists.json')
            .then(response => {
                console.log(response)
                this.setState({
                    lists: response.data
                })
            })
            .catch(error => console.log(error))
    }

    addNewList(title, description) {
        axios.post('/api/v1/lists.json', {
            title: title,
            description: description
        })
            .then(function (response) {
                console.log(response);
                const lists = [...this.state.lists, response.data]
                console.log(...this.state.lists)
                this.setState({ lists })
            })
            .catch(function (error) {
                console.log(error);
            });
    }

    render() {
        return (
            <div className="lists-container">
                {this.state.lists.map(list => {
                    return (<List list={list} key={list.id} />)
                })}
                <ListForm handleSubmit={this.addNewList} />
            </div>
        )
    }
}

export default ListContainer;
import React, { Component } from 'react';
import axios from 'axios';

class ListForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            title: '',
            description: ''
        };
    }

    handleChange = (e) => {
        this.setState({ [e.target.name]: e.target.value });
    }

    handleSubmit = (e) => {
        this.props.handleSubmit(this.state.title, this.state.description);
        e.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Title:
            <input name="title" type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <label>
                    Description:
            <textarea name="description" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
于 2019-10-09T06:52:23.243 回答
0

this.state.title使用&更改输入的值属性this.state.description

<input name="title" type="text" value={this.state.title} onChange={this.handleInputChange} />
<textarea name="description" value={this.state.description} onChange={this.handleInputChange} />

尝试使用打印信息

console.log("Form submitted with: ", this.state)

问候.bind(this)

  • 当任何事件触发时,都会将一个事件对象分配给回调函数。因此回调函数或事件处理程序失去对类的引用并this指向已调用的任何事件。
  • Bind 创建一个新函数,将 this 设置为传递给 bind() 的第一个参数
  • 除了.bind(this)箭头功能需要照顾this。但对于长层次结构来说并不可取。
于 2019-10-09T06:40:58.690 回答