【问题标题】:I am trying to capture data from my input fields on the lowest level component我正在尝试从最低级别组件的输入字段中捕获数据
【发布时间】:2025-12-02 04:10:01
【问题描述】:

我的 state 位于我的 APP 级组件中,我正在尝试捕获放入表单组件中的数据。我正在使用钩子,但我无法弄清楚我做错了什么!

我尝试将状态置于表单级别,但它返回未定义,我的最终目标是将此数据发送到 firebase,并将其显示在我的应用程序另一个页面上的表格中。

应用程序

import React, { useState, createRef } from "react";
import { render } from "react-dom";

import Header from "./components/Header";
import About from "./components/About";

const App = () => {
  const [date, setDate] = useState("");
  const [name, setName] = useState("");
  const [hours, setHours] = useState("");
  const [description, setDescription] = useState("");

  return (
    <div>
      <Header />
    </div>
  );
};

render(<App />, document.getElementById("root"));

**HEADER/ROUTER 组件

import React from "react";
import { render } from "react-dom";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  NavLink,
  Link
} from "react-router-dom";

import Home from "./pages/home/Home";
import Data from "./pages/data/Data";
import About from "./pages/about/About";
import Contact from "./pages/contact/Contact";


import "../style.css";

const Header = () => {
  return (
    <Router>
      <div>
        <nav className="navbar">
          <NavLink className="link nav-item" to="/entry">
            Time Entry
          </NavLink>
          <NavLink className="link nav-item" to="/data">
            Data
          </NavLink>
          <NavLink className="link nav-item-right" to="/about">
            About
          </NavLink>
          <NavLink className="link nav-item-right" to="/contact">
            Contact
          </NavLink>
        </nav>

        {/* A <Switch> looks through its children <Route>s and
            renders the first one that matches the current URL. */}
        <Switch>
          <Route exact path="/entry" component={Home} />
          <Route exact path="/data" component={Data} />
          <Route exact path="/about" component={About} />
          <Route exact path="/contact" component={Contact} />
        </Switch>
      </div>
    </Router>
  );
};

export default Header;

主页组件

import React, { Fragment } from "react";

import InputForm from "./Form";

const Home = props => {
  return (
    <Fragment>
      <InputForm />
    </Fragment>
  );
};

export default Home;

FORM 组件

import React, { Fragment, useState, createRef } from "react";
import { Button, Form, FormGroup, Label, Input, FormText } from "reactstrap";

const InputForm = props => {


  const dateEntry = createRef();
  const nameEntry = createRef();
  const hourEntry = createRef();
  const descriptionEntry = createRef();

  const handleClick = e => {
    e.preventDefault();
    setDate(dateEntry.current.value);
    setName(nameEntry.current.value);
    setHours(hourEntry.current.value);
    setDescription(descriptionEntry.current.value);
    // console.log(nameEntry.current.value);
  };

  return (
    <Form className="data-entry">
      <FormGroup className="form-entry-items">
        <Label className="label">Date</Label>
        <Input type="date" className="input" ref={dateEntry} />
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Lease Acconting Manager Name</Label>{" "}
        <Input type="text" className="input" ref={nameEntry} />
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Hours Worked</Label>{" "}
        <Input className="input" ref={hourEntry}/>
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Description</Label>{" "}
        <Input type="textarea" className="input" ref={descriptionEntry}/>
      </FormGroup>
      <Button onClick={handleClick}>Submit</Button>
    </Form>
  );
};

export default InputForm;

【问题讨论】:

  • 您没有根据该代码在任何地方导入Home。那正确吗?我会在App 中期待它。
  • 如果你想重用表单的处理程序,一个很好的模式可以让你免于丢失 propdrilling 将使用减速器或类似的东西。其他方法是将您的处理程序传递给 InputForm。
  • 我刚刚上传了我的 header/router 组件以显示所有内容的导入位置,我正在尝试学习 React Router...

标签: javascript reactjs state react-props reactstrap


【解决方案1】:

首先您应该质疑为什么要使用仅由 InputForm 使用的值来设置 APP 的状态。如果您只是打算在 InputForm 中使用它们,您应该将您的状态移动到该组件。

也许只需在 InputForm 中设置state,而不是使用createRef,这样您就可以在那里处理它们而无需propdrilling 或其他东西。

import React, { Fragment, useState, createRef } from "react";
import { Button, Form, FormGroup, Label, Input, FormText } from "reactstrap";

const InputForm = props => {

  const [date, setDate] = useState("");
  const [name, setName] = useState("");
  const [hours, setHours] = useState("");
  const [description, setDescription] = useState("");

  /* Im not sure How this works inside your component Input, but why dont just use a onChange?*/
  const dateEntry = createRef();
  const nameEntry = createRef();
  const hourEntry = createRef();
  const descriptionEntry = createRef();

  const handleInput = ( e, type)  => {
    switch( type ){
     case'name':
       setName( e.target.value );
     break;
     case'date':
       setDate( e.target.value );
     break;
    case'description':
       setDescription( e.target.value );
     break;
     case'hours':
       setHours( e.target.value );
     break;
    }
  }

  const handleClick = e => {
    e.preventDefault();
    //Just submit your data or something...  
  };

  return (
    <Form className="data-entry">
      <FormGroup className="form-entry-items">
        <Label className="label">Date</Label>
        <Input type="date" className="input" ref={dateEntry} onChange={ e => {handleChange( e, 'date') } } />
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Lease Acconting Manager Name</Label>{" "}
        <Input type="text" className="input" ref={nameEntry} onChange={ e => {handleChange( e, 'name' ) } } />
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Hours Worked</Label>{" "}
        <Input className="input" ref={hourEntry} onChange={ e => {handleChange( e, 'hours') } }/>
      </FormGroup>
      <FormGroup className="form-entry-items">
        <Label className="label">Description</Label>{" "}
        <Input type="textarea" className="input" ref={descriptionEntry} onChange={ e => {handleChange( e, 'description') } }/>
      </FormGroup>
      <Button onClick={handleClick}>Submit</Button>
    </Form>
  );
};

export default InputForm;

如果您需要从任何其他组件访问 Form 值,请尝试使用 context 来实现相同的功能,并可能尝试为它们添加一些 actions 和 减速器。

如果您需要更多信息,请查看: Context Docs, Reducer Docs

【讨论】:

    【解决方案2】:

    您最好使用react redux,但如果您不想这样做,您应该创建一个应用程序级函数并将其分配给所有子级,直到您将使用 onchage 回调的InputForm 组件在Input 中将事件传递回父级。根据父组件App 的函数实现,您将值设置为 state,propergation 应该类似于

    const App = () => {
      const [date, setDate] = useState("");
      const [name, setName] = useState("");
      const [hours, setHours] = useState("");
      const [description, setDescription] = useState("");
     handleChange = (e) => {
      //logic to set the specific value to state
      // you can use e.target.value as well as e.target.name to capture the value and decice which state variable to update. eg.
      if(e.target.name =="name") setName(e.target.value)
    //do same for all the other state variables
     }
      return (
        <div>
          <Header handleChange={handleChange } />
        </div>
      );
    };
    
    render(<App />, document.getElementById("root"));
    

    然后在 Header 组件内部你有它如下

    const Header = (props) => {
      return (
        <Router>
          <div>
            <nav className="navbar">
              <NavLink className="link nav-item" to="/entry">
                Time Entry
              </NavLink>
              <NavLink className="link nav-item" to="/data">
                Data
              </NavLink>
              <NavLink className="link nav-item-right" to="/about">
                About
              </NavLink>
              <NavLink className="link nav-item-right" to="/contact">
                Contact
              </NavLink>
            </nav>
    
            {/* A <Switch> looks through its children <Route>s and
                renders the first one that matches the current URL. */}
            <Switch>
              <Route exact path="/entry" render={(props) => <Home {...props} />}  />
              <Route exact path="/data" component={Data} />
              <Route exact path="/about" component={About} />
              <Route exact path="/contact" component={Contact} />
            </Switch>
          </div>
        </Router>
      );
    };
    
    export default Header;
    

    那么home组件会如下

    import React, { Fragment } from "react";
    
    import InputForm from "./Form";
    
    const Home = props => {
      return (
        <Fragment>
          <InputForm handleChange={props.handleChange} />
        </Fragment>
      );
    };
    
    export default Home; 
    

    现在您可以在表单级别执行以下操作

    import React, { Fragment, useState, createRef } from "react";
    import { Button, Form, FormGroup, Label, Input, FormText } from "reactstrap";
    
    const InputForm = props => {
    //using the handleChange function propergated from the parent component we will send the event and use it at the parent to collect the name and value artribute of the input. 
    
      return (
        <Form className="data-entry">
          <FormGroup className="form-entry-items">
            <Label className="label">Date</Label>
            <Input type="date" className="input" onChange={(e)=>props.handleChange(e)}/>
          </FormGroup>
          <FormGroup className="form-entry-items">
            <Label className="label">Lease Acconting Manager Name</Label>{" "}
            <Input name="name"  onChange={(e)=>props.handleChange(e)} type="text" className="input"  />
          </FormGroup>
          <FormGroup className="form-entry-items">
            <Label className="label">Hours Worked</Label>{" "}
            <Input name="hours" className="input" onChange={(e)=>props.handleChange(e)}/>
          </FormGroup>
          <FormGroup className="form-entry-items">
            <Label className="label">Description</Label>{" "}
            <Input type="textarea" name="description" className="input" onChange={(e)=>props.handleChange(e)}/>
          </FormGroup>
          <Button >Submit</Button>
        </Form>
      );
    };
    
    export default InputForm;
    

    【讨论】:

    • 这仍然会抛出props.handleChange不是函数的错误
    • @rstowe1 哪个组件抛出错误是InputForm
    • 是的,从 InputForm 更改时出现错误
    • 您应该回溯并查看 handleChange 作为函数丢失的位置,如果您没有错过名称。追溯每个组件并执行console.log(typeof props.handleChange);
    • 除了在未定义的 App 组件中之外,它在任何地方都作为函数接收