【问题标题】:React - passing state downReact - 向下传递状态
【发布时间】:2021-05-26 07:07:31
【问题描述】:

我正在用 React 构建一个简历创建者。我有一个表单,一个预览组件,它们最接近的父组件是 Main。我想要实现的是,当用户在表单字段中输入时,右侧的预览字段会使用表单中的数据自动更新,但我无法让它工作。这是我在 React 中的第一个项目,我不能使用钩子或函数组件。我知道我做错了什么,但无法确定是什么。

主要组件

import React, { Component } from "react";
import Form from "./form/Form";
import Preview from "./formpreview/Preview";

class Main extends Component {
  constructor(props) {
    super(props);
    this.state = {
      firstName: "",
      lastName: "",
      title: "",
      address: "",
      phoneNum: "",
      email: "",
      description: "",
    };

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

  handleSubmit = (event) => {
    event.preventDefault();
  };

  handleInputChange = (event) => {
    this.setState = {
      [event.target.name]: event.target.value,
    };
  };

  render() {
    const { firstName } = this.state;
    return (
      <div className="main">
        <Form
          submitForm={this.handleSubmit}
          changeInput={this.handleInputChange}
          firstName={firstName} lastName={lastName} title= 
          {title} address={address} phoneNum={phoneNum}
          email={email} description={description}
        />
        <Preview onChange={this.handleInputChange} 
         firstName={firstName} lastName={lastName} title= 
          {title} address={address} phoneNum={phoneNum}
          email={email} description={description}/>
      </div>
    );
  }
}

表单组件

import React, { Component } from "react";
import Personal from './buildingblocks/PersonalInfo';
import Experience from './buildingblocks/Experience';
import Education from './buildingblocks/Education';
import Buttons from './buildingblocks/FormButtons';

class Form extends Component {
   constructor(props) {
     super(props);
     this.state = {
       firstName: this.props.firstName,
       lastName: this.props.lastName,
       title: this.props.title,
       address: this.props.address,
       phoneNum: this.props.phoneNum,
       email: this.props.email,
       description: this.props.description
     }
   }

   submitForm = () => {
     this.props.submitForm()
   }

   changeInput = () => {
     this.props.changeInput()
   }

  
  render() {
    const {firstName, lastName, title, address, phoneNum, email, description} = this.state;
  
    return (
        <form className="cvForm" onSubmit={this.submitForm} onChange={this.changeInput}>
          <Personal firstName={firstName} lastName={lastName} title={title} address={address} phoneNum={phoneNum} email={email} description={description}/>

          <Experience />

          <Education />

          <Buttons />

        </form>
    );
  }
}

export default Form;

预览组件

import React, { Component } from "react";

class Preview extends Component {

  constructor(props) {
    super(props);
    this.state = {
      firstName: this.props.firstName,
      lastName: this.props.lastName,
      title: this.props.title,
      address: this.props.address,
      phoneNum: this.props.phoneNum,
      email: this.props.email,
      description: this.props.description
    }
  }

  submitForm = () => {
    this.props.submitForm()
  }

  changeInput = () => {
    this.props.changeInput()
  }


  render() {
    const {firstName, lastName, title, address, phoneNum, email, description} = this.state;

    return (
      <div className="cvPreview">
        <div className="gridItem nameItem">
          <h1>{firstName} </h1>
          <h3>Data engineer</h3>
        </div>
       
...
    );
  }
}

我没有包含所有预览组件,因为它只是元素。我知道我没有正确执行此操作,我收到 TypeError “无法读取未定义的属性'目标'”,我很确定我不应该多次定义这些道具,但在我尝试了一切之后,这是我的最后一枪。我卡住了,求助。

【问题讨论】:

  • 为什么不能使用函数式组件和 React hooks?卡在较旧的 React 版本中?
  • 部分课程。我想首先要熟悉类组件。
  • 在您的表单组件中,您有this.props.changeInput()。但是该函数期望事件作为参数。所以你应该有changeInput = (event) =&gt; { this.props.changeInput(event) }(虽然我不能100%确定当你将onChange直接附加到&lt;form/&gt;元素时触发的事件类型,所以也许打印出来看看)。
  • 当你将类组件从新版本的 react 中移出时,你最终可能会拥有很多不推荐使用的组件...
  • @ChristianMoen AFAIK React 没有提到从 React 中删除类,太多的依赖项。从 2019 年 2 月 6 日开始的这个 blog post 中没有介绍钩子,或者我知道的任何内容。你有引用吗?

标签: javascript reactjs state react-props


【解决方案1】:

问题

主要

  1. handleInputChange this.setState 应该是一个函数调用。

    handleInputChange = (event) => {
      const { name, value } = event.target;
      this.setState({
        [name]: value,
      });
    };
    

表格

  1. 将传递的 props 存储在本地组件状态中是 anti-pattern 在 React 中,只需直接引用 prop 值即可。如果您将它们存储在 state 中,那么您必须还实现 componentDidUpdate,这样您就可以在 props 更新时更新保存在 state 中的本地缓存(即更新的 state在父母中),这只是额外的不必要的工作。

  2. changeInput 处理程序不会消耗onChange 事件,也不会将其传递给this.props.changeInput,但与上一点类似,只需将this.props.changeInput 附加到需要它的元素。

  3. 需要props.changeInput 回调的子组件是呈现输入的组件,即在您的情况下,它似乎是Personal 组件。

    class Form extends Component {
      render() {
        const {
          address,
          changeInput,
          description,
          email,
          firstName,
          lastName,
          phoneNum,
          submitForm,
          title,
        } = this.props;
    
        return (
          <form className="cvForm" onSubmit={submitForm}>
            <Personal
              onChange={changeInput} // <-- pass change handler here
              firstName={firstName}
              lastName={lastName}
              title={title}
              address={address}
              phoneNum={phoneNum}
              email={email}
              description={description}
            />
    
            ...
          </form>
        );
      }
    }
    

预览

  1. 所有与Form 组件相同的cmets。不要在本地存储传递的props,直接使用this.props.changeInput回调。由于这是预览版,它可能不需要onChange 处理程序。

    class Preview extends Component {
      render() {
        const {
          firstName,
          lastName,
          title,
          address,
          phoneNum,
          email,
          description
        } = this.props;
    
        return (
          <div className="cvPreview">
            <div className="gridItem nameItem">
              <h1>
                {title} {firstName} {lastName}
              </h1>
              <h3>Data engineer</h3>
              ... other fields
            </div>
          </div>
        );
      }
    }
    

演示

【讨论】:

  • 我已经做到了。当我 console.log 目标值时,它会显示输入框中的值。没有错误了。但我仍然无法在右侧组件(预览组件)上打印它们。预览:return (

    {firstName} {lastName}

    也许我没有通过 onChange 它应该在哪里?
  • @jsme 这完全有可能。您之前将props.changeInput 传递给表单,但它需要传递给呈现输入的组件,我假设它是传递字段值的Personal 组件。我已经更新了我的答案以明确指出这一点,并且还包括一个 running 代码和框演示。请检查更新。
  • 我做到了!这是一个非常有用的解决方案。最后一切正常。
  • @jsme 太好了!乐意效劳。如果此答案有助于解决您的问题/问题,那么我邀请您接受它。不要忘记在 stackoverflow 上为您认为有帮助/有用的答案和 cmets 投票。干杯,祝你好运。
  • 接受!不幸的是,当我投票时,它说我没有足够的声誉,但它被记录下来了。所以我想它会在我再收集 4 个代表时显示出来。
【解决方案2】:

问题在于您的 handleInputChangesetState 应该是一个函数调用。

handleInputChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value,
    });
  };

这就是 setState API 的样子 React setState 。我还看到您的状态取决于 Preview 组件中的道具。

 this.state = {
       firstName: this.props.firstName,
       lastName: this.props.lastName,
       title: this.props.title,
       address: this.props.address,
       phoneNum: this.props.phoneNum,
       email: this.props.email,
       description: this.props.description
     }

这不是必需的,因为您将状态作为 props 传递给您的子组件。当您的子组件的道具发生变化(父组件的状态发生变化)时,您的子组件将始终重新渲染。

所以在您的预览组件中,您现在可以删除状态并拥有它

const {firstName, lastName, title, address, phoneNum, email, description} = this.props;

@danAbramov 的这篇博客解释了当状态依赖于 props 时可能面临的问题。

state dependent on props

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签