React(十)- React拓展:setState、lazyLoad以及Hook

React(十)- React拓展:setState、lazyLoad以及Hook

  • 一. setState拓展
    • 1.1 写法1
    • 1.2 写法2
    • 1.3 总结
  • 二. lazyLoad拓展
  • 三. Hook拓展
    • 3.1 StateHook
      • 总结1
    • 3.2 EffectHook
      • 总结2
    • 3.3 RefHook

React系列文章导航

一. setState拓展

页面效果图如下:
React(十)- React拓展:setState、lazyLoad以及Hook_第1张图片

1.1 写法1

state = { count: 0 }

add = () => {
    const { count } = this.state
    this.setState({ count: count + 1 })
}
render() {
    return (
        <div>
            <h1>当前和为{this.state.count}</h1>
            <button onClick={this.add}>1</button>
        </div>
    )
}

1.2 写法2

add = () => {
    const { count } = this.state
    // 该回调函数是调用完render()后再进行回调,因此该回调一般用来获取更新后的状态值
    // this.setState({ count: count + 1 }, () => {
    //     console.log(this.state.count)
    // })

    this.setState(state => ({ count: state.count + 1 }))
}

看起来写法2和写法1没有什么区别,只不过写成了个箭头函数而已,但是希望大家知道,写法2的情况下,我还可以接收其他参数,比如父组件App传入的参数,那么我在写法2中就可以这么写:

this.setState((state, props) => {
    console.log(props)
    return { count: state.count + 1 }
})

然后父类App组件中随意传入一个参数:
React(十)- React拓展:setState、lazyLoad以及Hook_第2张图片
此时点击页面的加1按钮后:可以发现获取到了对应的props
React(十)- React拓展:setState、lazyLoad以及Hook_第3张图片

1.3 总结

写法1:

  • setState(stateChange, [callback])------对象式的setState
  • stateChange为状态改变对象(该对象可以体现出状态的更改)。
  • callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用。

写法2:

  • setState(updater, [callback])------函数式的setState
  • updater为返回stateChange对象的函数。
  • updater可以接收到stateprops
  • callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。

二. lazyLoad拓展

lazyLoad顾名思义,懒加载,一般在我们项目特别大的时候去使用它。用的最多的就是路由。案例如下:

项目结构如下:
React(十)- React拓展:setState、lazyLoad以及Hook_第4张图片
About组件:

import React, { Component } from 'react'

export default class About extends Component {
    render() {
        return (
            <div>
                <h2>我是About组件</h2>
            </div>
        )
    }
}

Home组件:

import React, { Component } from 'react'

export default class Home extends Component {
    render() {
        return (
            <div>
                <h2>我是Home组件</h2>
            </div>
        )
    }
}

lazyLoad组件:

import React, { Component, lazy, Suspense } from 'react'
import { Link, Route } from 'react-router-dom'

// import Home from './About'
// import About from './Home'

const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </div>
        </div>
Î          <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <Link className="list-group-item" to="/about">About</Link>&nbsp;&nbsp;&nbsp;
              <Link className="list-group-item" to="/home">Home</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                <Suspense fallback={<h1>Loading...</h1>}>
                  {/**注册路由 */}
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                </Suspense>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

App组件:

import React, { Component } from 'react';
import Demo from './components/2_lazyLoad'


class App extends Component {
    render() {
        return (
            <div>
                <Demo />
            </div>
        );
    }
}
export default App;

入口文件index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>
    , document.getElementById('root'))

测试步骤如下:
1.运行项目,按F12,点击下图图标:
React(十)- React拓展:setState、lazyLoad以及Hook_第5张图片
2.选择Fast3G:(降低页面加载速度,可以这么理解)
React(十)- React拓展:setState、lazyLoad以及Hook_第6张图片
3.点击About导航:
React(十)- React拓展:setState、lazyLoad以及Hook_第7张图片
4.点击Home导航:
React(十)- React拓展:setState、lazyLoad以及Hook_第8张图片
可见有一个明显的加载过程,这里说个问题:
我们一般项目中引入组件的写法是:

import Home from './About'

但是这种写法,会导致页面初次加载的时候,就去将Home组件给加载进来

假设我们有一个非常大的页面,里面包含了1W个组件,那么我们在使用过程中,万一只需要用到其中1个组件,那根据上面的写法,岂不是白白的将剩下9999个组件都进行了渲染?岂不是很浪费页面的加载时间。

因此,我们需要按需加载,即懒加载,只有当组件需要用到的时候,我们再加载。

步骤:

  1. 将上述的import方式改为:
const Home = lazy(() => import('./Home'))
  1. 同时通过< Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面,同时定义一个回调,例如:
<Suspense fallback={<h1>loading.....</h1>}>
    <Switch>
        <Route path="/xxx" component={Xxxx}/>
        <Redirect to="/login"/>
    </Switch>
</Suspense>

三. Hook拓展

Hook是React16.8.0中新增加的特性。可以让你再函数组件中使用state以及其他的React特性。

有3个常用的Hook:

  • StateHook:React.useState()
  • EffectHook:React.Effect()
  • RefHook:React.useRef()

3.1 StateHook

StateHook让函数组件也可以有state状态,并进行状态数据的读写操作。

import React, { Component } from 'react'

// 类式组件
// export default class Demo extends Component {
//     state = { count: 0 }

//     add = () => {
//         this.setState(state => ({ count: state.count + 1 }))
//     }
//     render() {
//         return (
//             
//

当前和为{this.state.count}

// //
// ) // } // } // 函数式组件 function Demo() { return ( <div> <h1>当前和为{this.state.count}</h1> <button onClick={this.add}>1</button> </div> ) } export default Demo

这时候可以发现页面:
React(十)- React拓展:setState、lazyLoad以及Hook_第9张图片

因为函数式组件,没有this 因此更改如下:

 // 函数式组件
function Demo() {
    // 此时获得的a对象是一个数组,useState中传入的参数代表初始值
    const [count, setCount] = React.useState(0)
    // 若有个变量为name,那么可以仿照该写法就是:
    // const [name ,setName] = React.useState('tom')

    function add() {
        setCount(count + 1)
        // 第二种写法
        // setCount(count => count + 1)
    }
    return (
        <div>
            <h1>当前和为:{count}</h1>
            <button onClick={add}>1</button>
        </div>
    )
}

那么依旧可以有类式组件的效果,即更改state值。

React(十)- React拓展:setState、lazyLoad以及Hook_第10张图片

总结1

  1. StateHook让函数组件也可以有state状态, 并进行状态数据的读写操作。
  2. 语法: const [xxx, setXxx] = React.useState(initValue)
  3. useState()说明:

参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数

(4). setXxx()2种写法:

setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值


3.2 EffectHook

EffectHook用来在函数组件中执行副作用操作。

场景:打开上述的求和案例页面,和能够实现自增长的加1,并且增加卸载按钮用来卸载组件。

那么类式组件写法:

class Demo extends Component {
    state = { count: 0 }

    add = () => {
        this.setState(state => ({ count: state.count + 1 }))
    }

    componentDidMount() {
        this.timer = setInterval(() => {
            this.setState(state => ({ count: state.count + 1 }))
        }, 1000);
    }
	// 卸载组件的时候,必须把相关的定时器给卸载了,否则控制台会输出报错信息。
    unmount() {
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }
	// 因此这里需要写componentWillUnmount,来负责定时器的关闭
    componentWillUnmount() {
        clearInterval(this.timer)
    }

    render() {
        return (
            <div>
                <h1>当前和为{this.state.count}</h1>
                <button onClick={this.add}>1</button>
                <button onClick={this.unmount}>卸载</button>
            </div>
        )
    }
}

函数式组件写法:

function Demo() {
    const [count, setCount] = React.useState(0)

    function add() {
        setCount(count + 1)
    }

    React.useEffect(() => {
        let timer = setInterval(() => {
            setCount(count => count + 1)
        }, 1000)
        return () => {
            clearInterval(timer)
        }
    }, [])

    function unmount() {
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }

    return (
        <div>
            <h1>当前和为:{count}</h1>
            <button onClick={add}>1</button>
            <button onClick={unmount}>卸载</button>
        </div>
    )
}

总结2

  1. EffectHook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)。
  2. React中的副作用操作,例如:

1.发ajax请求数据获取
2. 设置订阅 / 启动定时器
3. 手动更改真实DOM

  1. 语法和说明:
useEffect(() => { 
  // 在此可以执行任何带副作用操作
  return () => { // 在组件卸载前执行
    // 在此做一些收尾工作, 比如清除定时器/取消订阅等
  }
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
  1. 可以把useEffectHook看做如下三个函数的组合:

componentDidMount()
componentDidUpdate()
componentWillUnmount()


3.3 RefHook

需求:输入框输入文本,点击显示数据按钮,弹框并展示相应内容。

如下:
React(十)- React拓展:setState、lazyLoad以及Hook_第11张图片

类式组件写法:

class Demo extends Component {
    myRef = React.createRef()

    show = () => {
        alert(this.myRef.current.value)
    }

    render() {
        return (
            <div>
                <input type="text" ref={this.myRef} />
                <button onClick={this.show}>展示数据</button>
            </div>
        )
    }
}

函数式组件写法:(基本上一致,只需要注意不要加上this即可)

function Demo() {
    const myRef = React.useRef()

    function show() {
        alert(myRef.current.value)
    }
    return (
        <div>
            <input type="text" ref={myRef} />
            <button onClick={show}>展示数据</button>
        </div>
    )
}

你可能感兴趣的:(React)