首页 > 解决方案 > 更改事件与 React 和 Typescript 混为一谈

问题描述

我用 TypeScript 和 React.js 创建了一个简单的应用程序。我将 create-react-app 与 --scripts-version=react-scripts-ts 参数一起使用,并获得了一个可以工作的应用程序。

该应用程序现在只有 2 个组件:App.tsx,一个包含人员列表的有状态组件和 Person.tsx,一个包含人员数据和名称输入文本的无状态功能组件。

这是Person.tsx的代码:

import * as React from "react";

export interface IPersonProps {
  id: string;
  firstname: string;
  change: (event: React.ChangeEvent<HTMLInputElement>) => void;
}

export const Person: React.SFC<IPersonProps> = props => {
  return (
    <div>
      <h1>
        Hi {props.firstname}
      </h1>
      <input type="text" onChange={props.change} value={props.firstname} />
    </div>
  );
};

这是App.tsx的代码:

import * as React from "react";
import "./App.css";
import { Person, IPersonProps } from "./Person";

interface IAppState {
  persons: Array<IPersonProps>,
  showPersons: boolean;
}

class App extends React.Component<{}, IAppState> {

  readonly togglePersonsHandler = () => {
    const show = this.state.showPersons;
    this.setState({showPersons: !show});
  }

  readonly firstnameChangeHandler = (event:React.ChangeEvent<HTMLInputElement>, 
personId: string) => {
    const personIndex = this.state.persons.findIndex(person => {
      return person.id === personId;
    });
    const person = {
      ...this.state.persons[personIndex]
    }

    person.firstname = event.target.value;

    const persons = [...this.state.persons];
    persons[personIndex] = person;

    this.setState({
      persons: persons
    } as IAppState);
  }

  constructor(props: any, state: IAppState) {
    super(props, state);
    this.state = {
      persons: [
        { id: 'a', firstname: "Michael" } as IPersonProps,
        { id: 'b', firstname: "Mel"} as IPersonProps
      ],
      showPersons: false
    };
  }

  public render() {
    let persons = null;

    if (this.state.showPersons) {
      persons = (
        <div>
          {
            this.state.persons.map((person, index) => {
              return <Person 
                id={person.id}
                firstname={person.firstname} 
                key={person.id} 
                change={this.firstnameChangeHandler.bind(this, event,     person.id)} />
            })
          }
        </div>
      )
    }

    return (
      <div className="App">
        <h1>React</h1>
        <button onClick={this.togglePersonsHandler}>Toggle Persons</button>
        {persons}
      </div>
    );
  }  
}

export default App;

名字到输入字段的绑定通常有效,但不适用于第一次触发的更改事件。第一个更改事件在触发时获得一个空值,并且名字将被设置为一个空字符串。所有其他更改事件似乎都有效。如您所见,我正在使用 TypeScript,并希望尽可能地保持类型安全......

也许与事件绑定混在一起。非常欢迎任何帮助!

该应用程序如下所示: React app with event binding

标签: javascriptreactjstypescriptbinding

解决方案


事件绑定确实是这里的问题。为了使它工作,我必须将处理程序方法的调用(在渲染方法中)更改为:

<Person 
  id={person.id}
  firstname={person.firstname} 
  key={person.id} 
  change={this.firstnameChangeHandler.bind(null, person.id)} />

处理程序方法必须将其签名更改为

readonly firstnameChangeHandler = (personId: string, event:React.ChangeEvent<HTMLInputElement>) => {...}

有关部分绑定的文档可在以下位置找到:

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Partially_applied_functions


推荐阅读