仅供个人学习使用,源码请见文件末尾
1.React Hooks简介
React Hooks就是用函数的形式代替原来的继承类的形式,并且使用预函数的形式管理state,有Hooks可以不再使用类的形式定义组件了。这时候你的认知也要发生变化了,原来把组件分为有状态组件和无状态组件,有状态组件用类的形式声明,无状态组件用函数的形式声明。那现在所有的组件都可以用函数来声明了。
2.useState多状态声明
useState是react自带的一个hook函数,它的作用是用来声明状态变量。
const [ count , setCount ] = useState(0);useState这个函数接收的参数是状态的初始值(Initial state),它返回一个数组,这个数组的第0位是当前的状态值,第1位是可以改变状态值的方法函数。 所以上面的代码的意思就是声明了一个状态变量为count,并把它的初始值设为0,同时提供了一个可以改变count的状态值的方法函数。
接下来如何读取状态中的值
<p>You clicked {count} times</p>最后改变State中的值
<button onClick={()=>{setCount(count+1)}}>click me</button>直接调用setCount函数,这个函数接收的参数是修改过的新状态值。
注意:React是根据useState出现的顺序来确定的
3.useEffect代替生命周期函数
使用useEffect代替两个生命周期函数
componentDidMount和componentDidUpdate。
案例如下:
import React, { useState , useEffect } from 'react';
function Example(){
    const [ count , setCount ] = useState(0);
    //---关键代码---------start-------
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
    })
    //---关键代码---------end-------
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count+1)}}>click me</button>
        </div>
    )
}
export default Example;useEffect需注意事项:
- React首次渲染和之后的每次渲染都会调用一遍
useEffect函数,而之前我们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)。- useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数时异步执行的,而
componentDidMonut和componentDidUpdate中的代码都是同步执行的。
4.useEffect实现componentWillUnmount生命周期函数
componentWillUnmount生命周期函数:组件将要被卸载时执行.
useEffect解绑副作用
学习React Hooks 时,要改掉生命周期函数的概念,因为Hooks叫它副作用,所以componentWillUnmount也可以理解成解绑副作用。这里用useEffect来实现类似componentWillUnmount效果,先安装React-Router路由,进入项目根本录,使用npm进行安装。
npm install --save react-router-dom然后打开Example.js文件,进行改写代码,先引入对应的React-Router组件。
import { BrowserRouter as Router, Route, Link } from "react-router-dom"在文件中编写两个新组件,因为这两个组件都非常的简单,所以就不单独建立一个新的文件来写了。
function Index() {
    return <h2>Index Page</h2>;
}
function List() {
    return <h2>List-Page</h2>;
}有了这两个组件后,接下来可以编写路由配置,在以前的计数器代码中直接增加就可以了。
return (
    <div>
        <p>You clicked {count} times</p>
        <button onClick={()=>{setCount(count+1)}}>click me</button>
        <Router>
            <ul>
                <li> <Link to="/">首页</Link> </li>
                <li><Link to="/list/">列表</Link> </li>
            </ul>
            <Route path="/" exact component={Index} />
            <Route path="/list/" component={List} />
        </Router>
    </div>
)然后到浏览器中查看一下,看看组件和路由是否可用。如果可用,我们现在可以调整useEffect了。在两个新组件中分别加入useEffect()函数:
function Index() {
    useEffect(()=>{
        console.log('useEffect=>老弟,你来了!Index页面')
        )
    return <h2>Index page</h2>;
}
function List() {
    useEffect(()=>{
        console.log('useEffect=>老弟,你来了!List页面')
    })
    return <h2>List-Page</h2>;
}这时候我们点击Link进入任何一个组件,在浏览器中都会打印出对应的一段话。这时候可以用返回一个函数的形式进行解绑,代码如下:
function Index() {
    useEffect(()=>{
        console.log('useEffect=>老弟你来了!Index页面')
        return ()=>{
            console.log('老弟,你走了!Index页面')
        }
    })
    return <h2>JSPang.com</h2>;
  }这时候你在浏览器中预览,我们仿佛实现了componentWillUnmount方法。但这只是好像实现了,当点击计数器按钮时,你会发现老弟,你走了!Index页面,也出现了。这到底是怎么回事呐?其实每次状态发生变化,useEffect都进行了解绑。
useEffect的第二个参数
如何实现类似componentWillUnmount的效果那?这就需要请出useEffect的第二个参数,它是一个数组,数组中可以写入很多状态对应的变量,意思是当状态值发生变化时,我们才进行解绑。但是当传空数组[]时,就是当组件将被销毁时才进行解绑,这也就实现了componentWillUnmount的生命周期函数。
function Index() {
    useEffect(()=>{
        console.log('useEffect=>老弟你来了!Index页面')
        return ()=>{
            console.log('老弟,你走了!Index页面')
        }
    },[])
    return <h2>Index Page</h2>;
}为了更加深入了解第二个参数的作用,把计数器的代码也加上useEffect和解绑方法,并加入第二个参数为空数组。代码如下:
function Example(){
    const [ count , setCount ] = useState(0);
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
        return ()=>{
            console.log('====================')
        }
    },[])
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count+1)}}>click me</button>
            <Router>
                <ul>
                    <li> <Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    )
}这时候的代码是不能执行解绑副作用函数的。但是如果我们想每次count发生变化,我们都进行解绑,只需要在第二个参数的数组里加入count变量就可以了。代码如下:
function Example(){
    const [ count , setCount ] = useState(0);
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
        return ()=>{
            console.log('====================')
        }
    },[count])
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count+1)}}>click me</button>
            <Router>
                <ul>
                    <li> <Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    )
}这时候只要count状态发生变化,都会执行解绑副作用函数,浏览器的控制台也就打印出了一串=================。
5.useContext父子组件传值
在用类声明组件时,父子组件的传值是通过组件属性和props进行的,那现在使用方法(Function)来声明组件,已经没有了constructor构造函数也就没有了props的接收,那父子组件的传值就成了一个问题。React Hooks 为我们准备了useContext。useContext它可以帮助我们跨越组件层级直接传递变量,实现共享。需要注意的是useContext和redux的作用是不同的,一个解决的是组件之间值传递的问题,一个是应用中统一管理状态的问题,但通过和useReducer的配合使用,可以实现类似Redux的作用。
Context的作用就是对它所包含的组件树提供全局共享数据的一种技术。
createContext函数创建context
import React, { useState , createContext } from 'react';
//===关键代码
const CountContext = createContext()
function Example4(){
    const [ count , setCount ] = useState(0);
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count+1)}}>click me</button>
            {/*======关键代码 */}
            <CountContext.Provider value={count}>
            </CountContext.Provider>
        </div>
    )
}
export default Example4;useContext接收上下文变量
已经有了上下文变量,剩下的就是如何接收了,接收这个直接使用useContext就可以,但是在使用前需要新进行引入useContext。
import React, { useState , createContext , useContext } from 'react';引入后写一个Counter组件,只是显示上下文中的count变量代码如下:
function Counter(){
    const count = useContext(CountContext)  //一句话就可以得到count
    return (<h2>{count}</h2>)
}得到后就可以显示出来了,但是要记得在<CountContext.Provider>的闭合标签中,代码如下。
<CountContext.Provider value={count}>
    <Counter />
</CountContext.Provider>6.useReducer的使用
reducer是一个函数,这个函数接收两个参数,一个是状态,一个用来控制业务逻辑的判断参数。
新建一个js文件,然后用useReducer实现计数器的加减双向操作。
import React, { useReducer } from 'react';
function ReducerDemo(){
    const [ count , dispatch ] =useReducer((state,action)=>{
        switch(action){
            case 'add':
                return state+1
            case 'sub':
                return state-1
            default:
                return state
        }
    },0)
    return (
       <div>
           <h2>现在的分数是{count}</h2>
           <button onClick={()=>dispatch('add')}>Increment</button>
           <button onClick={()=>dispatch('sub')}>Decrement</button>
       </div>
    )
}
export default ReducerDemo7.useMemo优化性能
useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新之前)这个生命周期,也就是说我们没有办法通过组件更新前条件来决定组件是否更新。而且在函数组件中,也不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。useMemo和useCallback都是解决上述性能问题的。useCallback,目的是为了缓存方法(useMemo是为了缓存变量)。
import React , {useState,useMemo} from 'react';
function Example7(){
    const [xiaohong , setXiaohong] = useState('小红待客状态')
    const [zhiling , setZhiling] = useState('志玲待客状态')
    return (
        <>
            <button onClick={()=>{setXiaohong(new Date().getTime())}}>小红</button>
            <button onClick={()=>{setZhiling(new Date().getTime()+',志玲向我们走来了')}}>志玲</button>
            <ChildComponent name={xiaohong}>{zhiling}</ChildComponent>
        </>
    )
}父组件调用了子组件,子组件我们输出两个姑娘的状态,显示在界面上。代码如下:
function ChildComponent({name,children}){
    function changeXiaohong(name){
        console.log('她来了,她来了。小红向我们走来了')
        return name+',小红向我们走来了'
    }
    const actionXiaohong = changeXiaohong(name)
    return (
        <>
            <div>{actionXiaohong}</div>
            <div>{children}</div>
        </>
    )
}其实只要使用useMemo,然后给她传递第二个参数,参数匹配成功,才会执行。代码如下:
function ChildComponent({name,children}){
    function changeXiaohong(name){
        console.log('她来了,她来了。小红向我们走来了')
        return name+',小红向我们走来了'
    }
    const actionXiaohong = useMemo(()=>changeXiaohong(name),[name]) 
    return (
        <>
            <div>{actionXiaohong}</div>
            <div>{children}</div>
        </>
    )
}8.useRef获取DOM元素和变量
两个主要的作用:
- 用
useRef获取React JSX中的DOM元素,获取后你就可以控制DOM的任何东西了。但是一般不建议这样来作,React界面的变化可以通过状态来控制。- 用
useRef来保存变量.
源码地址:传送门 参考src/index.js中注释
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!