简体   繁体   English

将状态传递给子组件作为道具不起作用

[英]Passing state into child component as props not working

I'm trying to build an example CRUD app with React and React Router, and I can't figure out why state isn't passing into a child component the way I'm expecting it to. 我正在尝试使用React和React Router构建一个示例CRUD应用程序,但我不知道为什么状态没有按照我期望的方式传递给子组件。 When I hit the edit route, it renders the Edit component, which grabs the kitten I want from the database and sends it's info to a Form component which is used both for editing an existing kitten or adding a new one. 当我点击edit路径时,它将呈现“ Edit组件,该组件将从数据库中获取我想要的小猫,并将其信息发送到“表单”组件,该组件用于编辑现有小猫或添加新小猫。

Here's the Edit component: 这是Edit组件:

import React, { Component } from 'react';
import axios from 'axios';
import { match } from 'react-router-dom';
import Form from './Form';


export default class Edit extends Component {
    constructor(props) {
        super(props)

        this.state = {}
    }

    componentDidMount() {
        axios.get(`/updateKitten/${this.props.match.params.id}`)
        .then(res => {
            const kitten = res.data
            this.setState({ kitten })
            console.log(this.state.kitten.name)  //Sammy, or something
        })
        .catch(err => console.log(err))
    }

    render() {
        return (
                <Form 
                    name={this.state.kitten.name} // throws error or undefined
                    description={this.state.kitten.description} //throws error or undefined
                    route={this.props.match.params.id} 
                />
        )
    }
}

The Edit component passes name, description, and route to this Form component: Edit组件将名称,描述和路由传递给此Form组件:

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

export default class Add extends Component {
  constructor(props) {
    super(props)

    this.state = { name: this.props.name, description: this.props.description}

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e) {
    const name = e.target.name;
    const value = e.target.value;

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

  handleSubmit(e) {
    axios.post(`/addKitten/${this.props.route}`, this.state)
      .then(this.setState({ name: '', description: '' }))
    e.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>Name</label>
        <input type='text' name="name" value={this.state.name}
         onChange={this.handleChange}/>
        <label>Description</label>
        <input type='text' name="description" value={this.state.description}
          onChange={this.handleChange}/>
        <input type='submit' value='Submit' />
      </form>
    )
  }
}

And I get the following error: 我得到以下错误:

bundle.js:28950 Uncaught TypeError: Cannot read property 'name' of undefined

from trying to send that info as props to the Form component. 尝试将这些信息作为道具发送到Form组件。

What am I doing wrong? 我究竟做错了什么?

When your Edit component loads for the first time, it doesn't have a kitten . 首次加载“编辑”组件时,它没有kitten Hence the error. 因此,错误。

What you need to do is the create an empty kitten. 您需要做的是创建一只empty小猫。 In your Edit component... 在您的编辑组件中...

this.state = { kitten: {name:''} }

This will set the kitten's name to an empty string on the very first mount/render of your component. 这会将小猫的名字在组件的第一次安装/渲染时设置为空字符串。

Two things, 两件事情,

First: In your edit component, you have not initialised kitten state and you are setting it based on the API result. 首先:在您的编辑组件中,您尚未初始化小猫状态,而是根据API结果进行设置。 However, componentDidMount is called after the component has been called and hence the DOM has been rendered once and the first time it did not find any value as this.state.kitten.name or this.state.kitten.description . 但是,在组件被调用之后将调用componentDidMount,因此DOM已被渲染一次,并且第一次没有找到任何值为this.state.kitten.namethis.state.kitten.description值。

Its only after the API is a success that you set the kitten state. 只有在API成功后,您才能设置小猫状态。 Hence just make a check while rendering. 因此,只需在渲染时进行检查即可。

Second: You have console.log(this.state.kitten.name) after the setState function. 第二:在setState函数后面有console.log(this.state.kitten.name) However setState is asynchronous . 但是setState is asynchronous See this question: 看到这个问题:

Change state on click react js 更改点击React JS的状态

and hence you need to specify console.log in setState callback 因此,您需要在setState回调中指定console.log

You code will look like 您的代码看起来像

export default class Edit extends Component {
    constructor(props) {
        super(props)

        this.state = {}
    }

    componentDidMount() {
        axios.get(`/updateKitten/${this.props.match.params.id}`)
        .then(res => {
            const kitten = res.data
            this.setState({ kitten }. function() {
                  console.log(this.state.kitten.name)  //Sammy, or something
            })

        })
        .catch(err => console.log(err))
    }

    render() {
        return (
                <Form 
                    name={this.state.kitten.name || '' } 
                    description={this.state.kitten.description || ''} 
                    route={this.props.match.params.id} 
                />
        )
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM