This article has been machine-translated from Chinese. The translation may contain inaccuracies or awkward phrasing. If in doubt, please refer to the original Chinese version.
Event Handling
Handling Events – React (docschina.org)
- You need to pass a function as the event handler, rather than a string.
<button onClick={activateLasers}>
Activate Lasers
</button>
- You cannot prevent default behavior by returning
false. You must explicitly callpreventDefault.
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
When using React, you generally don’t need to use
addEventListenerto add listeners to already-created DOM elements. In fact, you only need to add listeners when the element is initially rendered. Declare event handling functions as methods in the class.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is essential to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Lists and Keys
Lists & Keys – React (docschina.org)
Keys
Keys help React identify which elements have changed, such as being added or removed. Therefore, you should give each element in an array a definitive identifier.
The best key for an element is a unique string that the element has within the list. Typically, we use the id from the data as the element’s key.
Keys Must Be Unique Among Siblings
Keys used among array elements should be unique among their sibling nodes. However, they don’t need to be globally unique. When we generate two different arrays, we can use the same key values.
Forms
In React, HTML form elements work somewhat differently from other DOM elements, because form elements typically maintain some internal state.
Controlled Components
In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the component’s state property and can only be updated using setState().
We can combine these two approaches to make React’s state the “single source of truth”. The React component that renders the form also controls what happens in the form during user input. A form input element whose value is controlled by React in this way is called a “controlled component.”
The textarea Tag
In HTML, the <textarea> element defines its text through its children:
<textarea>
Hello, this is text inside a text area
</textarea>
In React, <textarea> uses a value attribute instead. This makes forms using <textarea> very similar to forms using single-line inputs:
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'Please write an essay about your favorite DOM element.' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('Submitted essay: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Note that this.state.value is initialized in the constructor, so the text area has a default initial value.
Lifting State Up
Often, several components need to reflect the same changing data. We recommend lifting the shared state up to the closest common ancestor component. Let’s see how this works.
Lifting State Up – React (docschina.org)
We’ll start with a component called BoilingVerdict. It accepts a celsius temperature as a prop and prints whether it is enough to boil water.
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>; }
return <p>The water would not boil.</p>;}
Next, we’ll create a component called Calculator. It renders an <input> for entering the temperature and keeps its value in this.state.temperature.
Additionally, it renders the BoilingVerdict component based on the current input value.
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''}; }
handleChange(e) {
this.setState({temperature: e.target.value}); }
render() {
const temperature = this.state.temperature; return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset>
);
}
}
Adding a Second Input
Our new requirement is to provide a Fahrenheit input in addition to the existing Celsius input, and keep the two inputs synchronized.
We’ll extract a TemperatureInput component from Calculator, and add a new scale prop to it that can be either "c" or "f":
const scaleNames = { c: 'Celsius', f: 'Fahrenheit'};
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
const scale = this.props.scale; return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend> <input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
We can now modify the Calculator component to render two independent temperature input components:
We’ll extract a TemperatureInput component from Calculator, and add a new scale prop to it that can be either "c" or "f":
In a React application, any mutable data should have a single corresponding “source of truth.” Usually, state is first added to the component that needs it for rendering. Then, if other components also need this state, you can lift it up to the closest common ancestor. You should rely on the top-down data flow, rather than trying to synchronize state between different components.
While lifting state requires writing more “boilerplate” code than two-way binding, the benefit is that finding and isolating bugs takes less work. Since any state “lives” in a component and only that component can change it, the surface area for bugs is greatly reduced. Additionally, you can implement custom logic to reject or transform user input.
喜欢的话,留下你的评论吧~