七天接手react项目 —— state事件处理ref (2)

修改 Clock 组件的 render() 方法:

render() { + console.log(1) return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }

控制台输出:

1 ⑨ 1

组件一挂载就得渲染,输出第一行的 1,然后每过一秒就会在第二行输出,这里统计到第 9 秒。

所以,render() 执行 1 + N 次。N 在这里表示状态更改了 9 次。

公有实例字段优化 state 初始化

请看示例:

<script> class Dog { age = 18 constructor(name) { this.name = name } } let d = new Dog('peng') console.log('d: ', d); </script>

控制台输出:d: Dog {age: 18, name: 'peng'}

age = 18 等价于给实例定义了一个属性 age。于是我们可以将通过次语法来优化 state 的初始化。

优化前:

class Clock extends React.Component { constructor() { super() this.state = { date: new Date() } setInterval(this.tick.bind(this), 1000) } }

优化后:

class Clock extends React.Component { state = { date: new Date() } constructor() { super() setInterval(this.tick.bind(this), 1000) } }

Tip:setInterval() 通常会移出构造函数,例如放在某生命钩子函数中,所以整个构造函数 constructor() 都可以省略

在函数组件中使用 state

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性 —— 官网-Hook API 索引

前面我们一直是在 class 组件中使用 state。就像这样:

class Clock extends React.Component { state = { date: new Date(), name: 'pjl' } constructor() { super() setInterval(this.tick.bind(this), 1000) } tick() { this.setState({ date: new Date() }) } render() { return ( <div> <h1>Hello, world! {this.state.name}</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }

而通过 useState Hook 能让我们在函数组件使用 state。实现上述相同的功能:

function Clock() { // 一个 state 就得调用一次 useState() const [name] = React.useState('pjl') // 解构赋值 const [date, setDate] = React.useState(new Date()) setInterval(() => { // 更新 state setDate(new Date()) }, 1000) return ( <div> <h1>Hello, world! {name}</h1> <h2>It is {date.toLocaleTimeString()}.</h2> </div> ); }

一个 state 就得调用一次 useState(initialState)

React.useState 返回一个 state,以及更新 state 的函数

在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同

在后续的重新渲染中,useState 返回的第一个值将始终是更新后最新的 state

Tip:请问控制台输出几次 a:

function Clock() { console.log('a') // ... 不变 }

答案是:1 + N 次。Clock 函数被反复的调用,但 useState() 返回的第一个值始终是更新后最新的 state,所以能猜出 react 做了特殊处理

事件处理 事件命名采用小驼峰式

React 事件的命名采用小驼峰式(camelCase),而不是纯小写。例如在 html 中通常都是小写,就像这样:

// onclick - 小写 <button>click</button>

下面这个组件,每点击一次 button,控制台就会输出一次 lj:

class EventDemo1 extends React.Component { handleClick() { console.log('lj') } render() { return ( <button onClick={this.handleClick}> click </button> ); } }

Tip:使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串 —— 官网

倘若将 onClick 改成 onclick,浏览器控制台将报错如下:

Warning: Invalid event handler property `onclick`. Did you mean `onClick`? 事件中的 this

假如我们在 EventDemo1 中读取状态。就像这样:

class EventDemo1 extends React.Component { state = { name: 'lj' } handleClick() { console.log(typeof this) // 读取状态 console.log(this.state.name) } render() { return ( <button onClick={this.handleClick}> click </button> ); } }

控制报错:

undefined Uncaught TypeError: Cannot read properties of undefined (reading 'state')

我们根据错误信息能推测出在 handleClick() 方法中没有 this。

Tip:现在有一个事实:即我们自己的方法中没有 this,而 render() 方法中却有 this。猜测 react 只帮我们处理了 render() 方法中的 this。

所以,我们需要处理一下自定义方法中的 this。请看实现:

class EventDemo1 extends React.Component { state = { name: 'lj' } handleClick = () => { console.log(typeof this) console.log(this.state.name) } render() { // ... } }

每次点击 button,都会输出:

object lj

处理 this 的方法有两点:

将原型中的方法移到实例上来

使用箭头函数。由于箭头函数没有 this,而将箭头函数中的 this 输出来,却正好就是实例

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzgydf.html