3. 使用单一计算方法
现在,让我们重构handleAdd和handleSubtract方法。
我们使用两种几乎具有相同代码的独立方法来创建代码重复。 我们可以通过创建单个方法并将参数传递给标识加法或减法运算的函数来解决此问题。
// change the below code: <button type="button" className="btn" onClick={this.handleAdd}> Add </button> <button type="button" className="btn" onClick={this.handleSubtract}> Subtract </button> // to this code: <button type="button" className="btn" onClick={() => this.handleOperation('add')}> Add </button> <button type="button" className="btn" onClick={() => this.handleOperation('subtract')}> Subtract </button>
在这里,我们为onClick处理程序添加了一个新的内联方法,其中我们通过传递操作名称来手动调用新的handleOperation方法。
现在,添加一个新的handleOperation方法,并删除以前添加的handleAdd和handleSubtract方法。如下所示:
handleOperation = (operation) => { const number1 = parseInt(this.state.number1, 10); const number2 = parseInt(this.state.number2, 10); let result; if (operation === "add") { result = number1 + number2; } else if (operation === "subtract") { result = number1 - number2; } if (isNaN(result)) { this.setState({ errorMsg: "Please enter valid numbers." }); } else { this.setState({ errorMsg: "", result: result }); } };
完整代码如下:
import React from "react"; import "./styles.css"; export default class App extends React.Component { state = { number1: "", number2: "", result: "", errorMsg: "" }; onInputChange = (event) => { const name = event.target.name; const value = event.target.value; this.setState({ [name]: value }); }; handleOperation = (operation) => { const number1 = parseInt(this.state.number1, 10); const number2 = parseInt(this.state.number2, 10); let result; if (operation === "add") { result = number1 + number2; } else if (operation === "subtract") { result = number1 - number2; } if (isNaN(result)) { this.setState({ errorMsg: "Please enter valid numbers." }); } else { this.setState({ errorMsg: "", result: result }); } }; render() { return ( <div> <div className="input-section"> {this.state.errorMsg && ( <p className="error-msg">{this.state.errorMsg}</p> )} <label>First Number</label> <input type="text" name="number1" placeholder="Enter a number" value={this.state.number1} onChange={this.onInputChange} /> </div> <div className="input-section"> <label>Second Number</label> <input type="text" name="number2" placeholder="Enter a number" value={this.state.number2} onChange={this.onInputChange} /> </div> <div className="result-section"> Result: <span className="result">{this.state.result}</span> </div> <button type="button" className="btn" onClick={() => this.handleOperation("add")} > Add </button> <button type="button" className="btn" onClick={() => this.handleOperation("subtract")} > Subtract </button> </div> ); } }
4.使用ES6解构语法
在onInputChange方法中,我们有如下代码:
const name = event.target.name; const value = event.target.value;
我们可以使用ES6解构语法来简化它,如下所示:
const { name, value } = event.target;
在这里,我们从对象中提取name和value属性,event.target并创建局部name和value变量来存储这些值。
现在,在handleOperation方法内部,我们不必每次使用this.state.number1和时都引用状态 this.state.number2,而是可以预先分离出这些变量:
// change the below code: const number1 = parseInt(this.state.number1, 10); const number2 = parseInt(this.state.number2, 10); // to this code: let { number1, number2 } = this.state; number1 = parseInt(number1, 10); number2 = parseInt(number2, 10);
5.使用增强的对象字面量语法
如果您检查setState函数内部的函数调用handleOperation,则如下所示:
this.setState({ errorMsg: "", result: result });
我们可以使用增强的对象字面量语法来简化此代码。
如果属性名与变量名完全匹配,result: result那么我们可以跳过在冒号后面提到的部分。因此,上面的setState函数调用可以这样简化:
this.setState({ errorMsg: "", result });
6.将类组件转换为React Hooks
从React版本16.8.0开始,React添加了一种使用React Hooks
在函数组件内部使用状态和生命周期方法的方法。
**使用React Hooks可以使我们编写的代码短得多,并且易于维护和理解。**因此,让我们将上面的代码转换为使用React Hooks语法。
如果您不熟悉React Hooks,请查看React Hooks的介绍。
首先让我们将App组件声明为函数组件:
const App = () => { }; export default App;
要声明状态,我们需要使用useState
钩子,因此将其导入文件顶部。然后创建3个useState,一个用于将数字存储在一起作为对象。我们可以使用一个处理函数和两个其他useState调用来一起更新它们,以存储结果和错误消息。
import React, { useState } from "react"; const App = () => { const [state, setState] = useState({ number1: "", number2: "" }); const [result, setResult] = useState(""); const [errorMsg, setErrorMsg] = useState(""); }; export default App;
将onInputChange处理程序方法更改为此:
const onInputChange = () => { const { name, value } = event.target; setState((prevState) => { return { ...prevState, [name]: value }; }); };
在这里,我们使用updater语法设置状态,因为在使用React Hooks时,更新对象时状态不会自动合并。
因此,我们首先分散状态的所有属性,然后添加新的状态值。
将handleOperation方法更改为此:
const handleOperation = (operation) => { let { number1, number2 } = state; number1 = parseInt(number1, 10); number2 = parseInt(number2, 10); let result; if (operation === "add") { result = number1 + number2; } else if (operation === "subtract") { result = number1 - number2; } if (isNaN(result)) { setErrorMsg("Please enter valid numbers."); } else { setErrorMsg(""); setResult(result); } };
完整代码:
import React, { useState } from "react"; import "./styles.css"; const App = () => { const [state, setState] = useState({ number1: "", number2: "" }); const [result, setResult] = useState(""); const [errorMsg, setErrorMsg] = useState(""); const onInputChange = (event) => { const { name, value } = event.target; setState((prevState) => { return { ...prevState, [name]: value }; }); }; const handleOperation = (operation) => { let { number1, number2 } = state; number1 = parseInt(number1, 10); number2 = parseInt(number2, 10); let result; if (operation === "add") { result = number1 + number2; } else if (operation === "subtract") { result = number1 - number2; } if (isNaN(result)) { setErrorMsg("Please enter valid numbers."); } else { setErrorMsg(""); setResult(result); } }; return ( <div> <div className="input-section"> {errorMsg && <p className="error-msg">{errorMsg}</p>} <label>First Number</label> <input type="text" name="number1" placeholder="Enter a number" value={state.number1} onChange={onInputChange} /> </div> <div className="input-section"> <label>Second Number</label> <input type="text" name="number2" placeholder="Enter a number" value={state.number2} onChange={onInputChange} /> </div> <div className="result-section"> Result: <span className="result">{result}</span> </div> <button type="button" className="btn" onClick={() => handleOperation("add")} > Add </button> <button type="button" className="btn" onClick={() => handleOperation("subtract")} > Subtract </button> </div> ); }; export default App;
7.隐式返回对象
现在,我们已经优化了代码以使用现代ES6功能并避免了代码重复。我们可以做的另一件事就是简化setState函数调用。
如果检查处理程序中的当前setState函数调用onInputChange,则如下所示:
setState((prevState) => { return { ...prevState, [name]: value }; });
在箭头函数中,如果我们有这样的代码:
const add = (a, b) => { return a + b; }
然后我们可以简化它,如下所示:
const add = (a, b) => a + b;
之所以行之有效,是因为如果箭头函数主体中只有一条语句,那么我们可以跳过花括号和return关键字。这称为隐式收益。
因此,如果我们要从箭头函数返回这样的对象:
const getUser = () => { return { name: 'David, age: 35 } }
我们就不能像这样简化它:
const getUser = () => { name: 'David, age: 35 }
因为大括号表示函数的开始,因此上述代码无效。为了使其工作,我们可以将对象包装在圆括号中,如下所示:
const getUser = () => ({ name: 'David, age: 35 })
上面的代码与下面的代码等效:
const getUser = () => { return { name: 'David, age: 35 } }
因此,我们可以使用相同的技术来简化setState函数调用。
setState((prevState) => { return { ...prevState, [name]: value }; }); // the above code can be simplified as: setState((prevState) => ({ ...prevState, [name]: value }));
在React中经常使用这种将代码包装在方括号中的技术:
- 定义功能组件:
const User = () => ( <div> <h1>Welcome, User</h1> <p>You're logged in successfully.</p> </div> );
- 在react-redux中的mapStateToProps函数内部:
const mapStateToProps = (state, props) => ({ users: state.users, details: state.details });
- Redux action creator:
const addUser = (user) => ({ type: 'ADD_USER', user });
8.编写更好的React组件的额外技巧
如果我们有这样的组件:
const User = (props) => ( <div> <h1>Welcome, User</h1> <p>You're logged in successfully.</p> </div> );
然后希望将它仅进行测试或调试,而不是将代码转换为以下代码:
const User = (props) => { console.log(props); return ( <div> <h1>Welcome, User</h1> <p>You're logged in successfully.</p> </div> ); }
可以 || 像这样使用逻辑OR运算符():
const User = (props) => console.log(props) || ( <div> <h1>Welcome, User</h1> <p>You're logged in successfully.</p> </div> );
该console.log函数仅打印传递给它的值,但不返回任何内容–因此它将被评估为未定义||(…)。
并且由于||运算符返回第一个真实值,因此之后的代码||也将被执行。