React归纳总结笔记 1期

1.setState()的使用

setState()更新状态的2种写法

  1. setState(updater, [callback])

updater为返回stateChange对象的函数: (state, props) => stateChange
接收的state和props被保证为最新的

  1. setState(stateChange, [callback])

stateChange为对象
callback是可选的回调函数, 在状态更新且界面更新后才执行

  1. 总结:

对象方式是函数方式的简写方式
====如果新状态不依赖于原状态 ===> 使用对象方式
====如果新状态依赖于原状态 ===> 使用函数方式
如果需要在setState()后获取最新的状态数据, 在第二个callback函数中读取

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>01_setState()的使用</title>
</head>

<body>

  <div id="example"></div>

  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script src="https://cdn.bootcss.com/remarkable/1.7.1/remarkable.min.js"></script>

  <script type="text/babel">

  class A extends React.Component {

    state = {
      count: 1
    }

    test1 = () => {
      this.setState(state => ({count: state.count + 1}))
      console.log('test1 setState()之后', this.state.count)
    }

    test2 = () => {
      // const count = this.state.count + 1
      // this.setState({
      //   count
      // })
      this.setState({
        count: 3
      })
      console.log('test2 setState()之后', this.state.count)
    }

    test3 = () => {
      this.setState(state => ({count: state.count + 1}), () => { 
      	// 在状态更新且界面更新之后回调
        console.log('test3 setState callback()', this.state.count)
      })
    }

    render() {
      console.log('A render()')
      return (
        <div>
          <h1>A组件: {this.state.count}</h1>
          <button onClick={this.test1}>A 测试1</button>&nbsp;&nbsp;
          <button onClick={this.test2}>A 测试2</button>&nbsp;&nbsp;
          <button onClick={this.test3}>A 测试3</button>&nbsp;&nbsp;
        </div>
      )
    }
  }

  ReactDOM.render(<A/>, document.getElementById('example'))
</script>
</body>

</html>

代码示例是在网上看到这种方式的,之前学习React的时候都是脚手架创建项目,在里面学习语法。现在看到引入本地React库文件,学习Vue是引入本地库文件,这种方式还没有见到过,先做个笔记记录下来,方便以后查找。

2.setState()异步OR同步更新

异步 OR 同步?

  1. 异步 :在react控制的回调函数中

生命周期勾子 / react事件监听回调

  1. 同步:非react控制的异步回调函数中

定时器回调 / 原生事件监听回调 / promise回调 /…

	// 同步
    state = {
      count: 0,
    }
	
    /*
     react事件监听回调中, setState()是异步更新状态
     */
    update1 = () => {
      console.log('update1 setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('update1 setState()之后', this.state.count)
    }

    /*
     react生命周期勾子中, setState()是异步更新状态
     */
    componentDidMount () {
      console.log('componentDidMount setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('componentDidMount setState()之后', this.state.count)
    }

    render() {
      const {count} = this.state
      console.log('render()', count)
      return (
        <div>
          <h2 ref='count'>{count}</h2>
          <button onClick={this.update1}>更新1</button> ---
          <button onClick={this.update2}>更新2</button> &nbsp;
          <button onClick={this.update3}>更新3</button> &nbsp;
          <button onClick={this.update4}>更新4</button> ---
          <button onClick={this.update5}>更新5</button> &nbsp;
          <button onClick={this.update6}>更新6</button> &nbsp;
          <button onClick={this.update7}>更新7</button> &nbsp;
        </div>
      )
    }
  • react生命周期勾子中响应结果
    react生命周期勾子中响应结果
  • react事件监听回调中响应结果
    react事件监听回调中响应结果
    // 异步
    /*
    定时器回调 / 原生事件监听回调 / promise回调 /...
     */
    update2 = () => {
      setTimeout(() => {
        console.log('setTimeout setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('setTimeout setState()之后', this.state.count)
      })
    }
    
    update3 = () => {
      const h2 = this.refs.count
      h2.onclick = () => {
        console.log('onclick setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('onclick setState()之后', this.state.count)
      }
    }
    
    update4 = () => {
      Promise.resolve().then(value => {
        console.log('Promise setState()之前', this.state.count)
        this.setState(state => ({count: state.count + 1}))
        console.log('Promise setState()之后', this.state.count)
      })
    }
  • 定时器回调中响应结果
    定时器回调中响应结果
  • 原生事件监听回调中响应结果
    原生事件监听回调中响应结果
  • promise回调中响应结果
    promise回调中响应结果
	// setState(fn): 更新多次状态, 但只调用一次render()更新界面
    update5 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后', this.state.count)
      console.log('onclick setState()之前2', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后2', this.state.count)
    }
	
	// setState({}): 合并更新一次状态, 只调用一次render()更新界面
    update6 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后', this.state.count)
      console.log('onclick setState()之前2', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后2', this.state.count)
    }

    update7 = () => {
      console.log('onclick setState()之前', this.state.count)
      this.setState({count: this.state.count + 1})
      console.log('onclick setState()之后', this.state.count)

      console.log('onclick setState()之前2', this.state.count)
      this.setState(state => ({count: state.count + 1}))
      console.log('onclick setState()之后2', this.state.count)
    }
  • update5函数执行,setState(fn) 中响应结果
    update5函数执行,setState(fn) 中响应结果
  • update6函数执行,setState({}) 中响应结果
    update6函数执行,setState({}) 中响应结果

关于异步的setState()

  1. 多次调用, 如何处理?
setState()写法状态更新render()函数合并
setState({})合并更新一次状态只调用一次render()更新界面状态更新和界面更新都合并了
setState(fn)更新多次状态只调用一次render()更新界面状态更新没有合并, 但界面更新合并了
  1. 如何得到异步更新后的状态数据?

在setState()的callback回调函数中

3.Component 和 PureComponent 的区别

Component存在的问题?

1). 父组件重新render(), 当前组件也会重新执行render(), 即使没有任何变化
2). 当前组件setState(), 重新执行render(), 即使state没有任何变化

class Child extends React.Component {

  render() {
    console.log('child render')
    return <div>child</div>;
  }
}

class App extends React.Component {
  state = {
    a: 1,
  };

  render() {
    console.log('render');
    return (
      <>
        <button
          onClick={() => {
          	{/* 当前组件setState(), 重新执行render() */}
            this.setState({ a: 2 });
          }}
        >
          Click me
        </button>
        {/* 父组件重新render(), 当前组件也会重新执行render() */}
        <Child color={'red'}/>
      </>
    );
  }
}

解决Component存在的问题

优化组件render,使用shouldComponentUpdate(),重写shouldComponentUpdate()钩子函数
Java里面打印对象地址,会使用到重写toString()方法,类比理解

class Child extends React.Component {
	
	{/* 重写shouldComponentUpdate()钩子函数 */}
  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true
    }
  }

  render() {
    console.log('child render')
    return <div>child</div>;
  }
}

上面是在子组件里面重写shouldComponentUpdate()钩子函数,解决子组件里面数据无变化时,父组件渲染对应的子组件不跟着渲染。

1). 原因: 组件的componentShouldUpdate()默认返回true, 即使数据没有变化render()都会重新执行
2). 办法1: 重写shouldComponentUpdate(), 判断如果数据有变化返回true, 否则返回false
3). 办法2: 使用PureComponent代替Component
4). 说明: 一般都使用PureComponent来优化组件性能

PureComponent的基本原理

上面子组件重写shouldComponentUpdate()钩子函数改为使用PureComponent代替Component,代码如下:

class Child extends React.PureComponent {

  render() {
    console.log('child render')
    return <div>child</div>;
  }
}

1). 重写实现shouldComponentUpdate()
2). 对组件的新/旧state和props中的数据进行浅比较, 如果都没有变化, 返回false, 否则返回true
3). 一旦componentShouldUpdate()返回false不再执行用于更新的render()

4.列表key的问题

网上代码注释引用
网上代码注释

  const time = Date.now()

  state = {
    persons: [
      {id: time, name: 'Tom', age: 13},
      {id: time +1, name: 'Jack', age: 12},
    ]
  }
	
  render() {
  	const persons = this.state.persons
  	return (
  		<div>
  			<ul>
  				{	
  					{/* React循环渲染数据 */}
  					persons.map((p, index) =>
  					  <li key={index}>{p.id}--{p.name}--{p.age}--<input/></li>
  					)  
  				}
  			</ul>
  		</div>
  	)
  }

React循环渲染数据这里使用了ES6的 map方法遍历数组对象返回渲染元素,React里面没有Vue里面的v-for指令操作,因此使用map方法遍历渲染元素。
通过Vue类比,学习React便于理解记忆。

养成写博客的好习惯,记录下来出现的bug以及解决方案
每天进步一点点,慢一点才能更快
感觉是 哈哈

2022.3.7 合肥

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值