首页 > 解决方案 > 反应状态:未捕获的类型错误:无法读取未定义的属性“值”

问题描述

我正在关注 Wes Bos 的React for Beginners课程,在 State 视频中,他编写了以下代码:

import React, { Component } from 'react';

class AddFishForm extends Component {

    nameRef = React.createRef();
    priceRef = React.createRef();
    statusRef = React.createRef();
    descRef = React.createRef();
    imageRef = React.createRef();

    createFish = event => {
        event.preventDefault();
        const fish = {
            nameRef: this.nameRef.value.value,
            priceRef: parseFloat(this.priceRef.value.value),
            statusRef: this.statusRef.value.value, 
            descRef: this.descRef.value.value,
            imageRef: this.imageRef.value.value,
        }
        console.log(this); //or console.log(fish)
    }
    render() {
        return (
            <form className="fish-edit" onSubmit={this.createFish}>
                <input name="name" ref={this.nameRef} type="text" placeholder="Name"/>
                <input name="price" ref={this.priceRef} placeholder="Price"/>
                <select name="status" ref={this.statusRef}>
                    <option value="available">Fresh!</option>
                    <option value="unavailable">Sold Out!</option>
                </select>
                <textarea name="desc" ref={this.descRef} placeholder="Desc"/>
                <input name="image" ref={this.imageRef} type="text" placeholder="Image"/>
                <button type="submit">+ Add Fish</button>
            </form>
        )
    }
}

export default AddFishForm;

每当我尝试单击“添加鱼”按钮时,都会出现错误:

AddFishForm.js:14 Uncaught TypeError: Cannot read property 'value' of undefined
    at AddFishForm._this.createFish (AddFishForm.js:14)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
    at invokeGuardedCallback (react-dom.development.js:256)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:270)
    at executeDispatch (react-dom.development.js:561)
    at executeDispatchesInOrder (react-dom.development.js:583)
    at executeDispatchesAndRelease (react-dom.development.js:680)
    at executeDispatchesAndReleaseTopLevel (react-dom.development.js:688)
    at forEachAccumulated (react-dom.development.js:662)
    at runEventsInBatch (react-dom.development.js:816)
    at runExtractedEventsInBatch (react-dom.development.js:824)
    at handleTopLevel (react-dom.development.js:4820)
    at batchedUpdates$1 (react-dom.development.js:18932)
    at batchedUpdates (react-dom.development.js:2150)
    at dispatchEvent (react-dom.development.js:4899)
    at interactiveUpdates$1 (react-dom.development.js:18987)
    at interactiveUpdates (react-dom.development.js:2169)
    at dispatchInteractiveEvent (react-dom.development.js:4876)

我想在他的代码中指出某些事情。他不使用带有关联绑定语句的构造函数(props)函数,而是选择将 createFish 转换为箭头函数。我看到的几乎所有其他关于 State 的问题都使用构造函数。我应该效仿,还是可以使用箭头符号(尽管它还不是标准)?


此外,在相关StorePicker.js文件中,他编写了以下代码,旨在通过路由将您从 StorePicker 页面带到 App 页面。然而,当我在我的应用程序中单击“转到商店”按钮时,该应用程序只会重新加载而不会继续。我应该做些什么不同的事情?

代码StorePicker.js

import React, { Fragment } from 'react';
import { getFunName } from '../helpers';

class StorePicker extends React.Component { //OR: ...extends Component (if you import { Component }).
    constructor () {
            super();
            console.log('Create a component!')
            this.goToStore = this.goToStore.bind(this);
    }
    
    myInput = React.createRef();
    goToStore(event) {
        //1. Stop the form from submitting.
            event.preventDefault();
        //2. Get the text from that input. Not going to select using document.querySelector or jQuery here.
        /*IMPORTANT!
            We need to bind ‘this’ to the StorePicker component so that it remains accessible from a member function.
            Either declare a constructor, as shown at the top, or turn goToStore into a function w/ arrow notation.
            goToStore = (event) => {}
        */
            const storeName = this.myInput.value.value;
        //3. Change the page to /store/whatever-they-entered. This uses push state instead of actually moving to a new page.
            this.props.history.push(`/store/${storeName}`);
    }

    render() {
        return (
            <Fragment>
                <h1>StorePicker</h1>
                <form className="store-selector">
                    <h2>Please enter a store.</h2>
                    <input type="text" 
                        ref={this.myInput}
                        required placeholder="Store name"
                        defaultValue={getFunName()}>
                    </input>
                    <button type="submit">Visit Store »
                    </button>
                </form>
            </Fragment>
        )
    }
}

export default StorePicker;

对于Router.js

import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import StorePicker from './StorePicker';
import App from './App';
import NotFound from './NotFound';

const Router = () => (
    <BrowserRouter>
        <Switch>
            <Route exact path="/" component={StorePicker} />
            <Route path="/store/:storeId" component={App} />
            <Route component={NotFound} />  {/*Default catch-all. */}
        </Switch>
    </BrowserRouter>
);

export default Router;

标签: javascriptreactjsreact-native

解决方案


问题参考

访问 refs 时,需要访问current属性。

访问参考

当 ref 被传递给 in 中的元素时render,对节点的引用可以在currentref 的属性中访问。

ref.current.<property>

代码

const fish = {
  nameRef: this.nameRef.current.value,
  priceRef: parseFloat(this.priceRef.current.value),
  statusRef: this.statusRef.current.value, 
  descRef: this.descRef.current.value,
  imageRef: this.imageRef.current.value,
}

问题 1

他不使用带有关联绑定语句的构造函数(props)函数,而是选择将 createFish 转换为箭头函数。我看到的几乎所有其他关于 State 的问题都使用构造函数。我应该效仿,还是可以使用箭头符号(尽管它还不是标准)?

AddFishForm没有状态,并且所有作为函数的类属性都是箭头函数,因此它们不需要this在构造函数中显式绑定到它们。此外,您也可以在没有构造函数的情况下声明状态类属性。

class Foo extends Component {
  state = {...}
  ...

问题2

...应该通过路由将您从 StorePicker 页面带到 App 页面的代码。然而,当我在我的应用程序中单击“转到商店”按钮时,该应用程序只会重新加载而不会继续。我应该做些什么不同的事情?

这里的问题是按钮有type="submit"并且在一个表单中,当点击它会使表单采取默认操作,即尝试提交表单并重新加载页面。this.goToStore也似乎根本没有使用。

<form className="store-selector">
  <h2>Please enter a store.</h2>
  <input type="text" 
    ref={this.myInput}
    required
    placeholder="Store name"
    defaultValue={getFunName()}
  />
  <button type="submit"> // <-- causes form to submit and take default actions
    Visit Store »
  </button>
</form>

解决方案

  1. 将按钮类型更改为type="button"并添加一个onClick处理程序,onClick={this.goToStore}
  2. 附加this.goToStore到表单的onSubmit处理程序<form onSubmit={this.goToStore}>

我猜goToStore是为了被表格使用。

<form
  className="store-selector"
  onSubmit={this.goToStore}
>
  <h2>Please enter a store.</h2>
  <input type="text" 
    ref={this.myInput}
    required
    placeholder="Store name"
    defaultValue={getFunName()}
  />
  <button type="submit">
    Visit Store »
  </button>
</form>

推荐阅读