一,概述
它的作用就是让函数式组件也可以使用状态管理。
二,项目创建
1,创建项目
npx create-react-app react-hooks-demo
2,编写原有的项目结构
三,使用hooks来改造-----useState
关于 useState 的用法是,需要传入一个参数作为状态的初始值,当函数执行后会返回两个值,一个是当前状态的属性,一个是修改状态的方法。
于是修改为函数式组件:
import React ,{useState}from 'react';
function Example () {
const [count,setCount]=useState(0)
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>setCount(count+1)}>点我</button>
</div>
);
}
export default Example;
const [count,setCount]=useState(0)
就是初始化state中的count为0,然后还有一个改变count的值的方法setCount,这个setCount的用法,就是传入啥值,就把count改成啥值。
也就是说。[count,setCount],一个是读取值,一个是改变值。
至于这种写法,则是es6的数组解构赋值。
需要注意的点是,这个useState必须按顺序执行,也就是把某句不能放在条件判断语句中。
四,使用hooks来改造—useEffect
1,useEffect的第一个参数
useEffect用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作。
在没有react-hooks的时候,我们是利用class类组件的生命周期函数componentDidMount等来完成这些事情,现在改用react-hooks的useEffect方法了而已。
修改example为:
import React ,{useState,useEffect}from 'react';
function Example () {
const [count,setCount]=useState(0)
useEffect(()=>{
console.log(count)
})
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>setCount(count+1)}>点我</button>
</div>
);
}
export default Example;
实际上,它相当于同时取代了componentDidUpdate和componentDidMount两个生命周期函数,当组件创建和变化时都会执行一次里面的函数。
需要注意的是useEffect是异步的。
2,useEffect的第二个参数
上面说的第一个函数参数,是替代了组件创建和更新的生命周期函数,那组件销毁的生命周期函数呢?需要在这个函数中return一个箭头函数进行执行:
import React ,{useState,useEffect}from 'react';
import {BrowserRouter as Router,Route,Link} from 'react-router-dom'
function Index() {
useEffect(()=>{
console.log("第一个组件创建")
return ()=>{
console.log("第一个组件被销毁,这样写,只要state中数据变化,就会执行,为了销毁后就不执行,需要useEffect第二个参数,传入空值便可,或者传入监听的state值便可")
}
},[])
return <h2>第一个页面</h2>
}
function List() {
useEffect(()=>{
console.log("第二个组件创建")
return ()=>{
console.log("第二个组件被销毁")
}
})
return <h2>第二个页面</h2>
}
function Example () {
const [count,setCount]=useState(0)
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>setCount(count+1)}>点我</button>
<Router>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/list/">列表页</Link></li>
</ul>
<Route path="/" exact component={Index}></Route>
<Route path="/list/" component={List}></Route>
</Router>
</div>
);
}
export default Example;
如果不设useEffect第二个参数,则state数据变化或者重复点击该路由页面,都会执行这个函数。
要使这个路由页面被销毁后(第一个函数参数的return中的箭头函数执行后),不再反复执行,需要useEffect传入第二个参数,是个数组。要达到这个目的,只要是数组就可以了,若要监听该组件的某个state,只要把该shate写入即可,当该state变化则会执行。
传入第二个参数【】,每次 render 后比较数组的值没变化,不会在执行,等同于类组件中的 componentDidMount:
useEffect(() => {
console.log('useEffect with empty dependency')
}, [])
function Example () {
const [count,setCount]=useState(0)
useEffect(()=>{
console.log("组件创建")
return ()=>{
console.log("销毁")
}
},[count])
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>setCount(count+1)}>点我</button>
<Router>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/list/">列表页</Link></li>
</ul>
<Route path="/" exact component={Index}></Route>
<Route path="/list/" component={List}></Route>
</Router>
</div>
);
}
当点击按钮的时候,就会执行useEffect中的第一个函数,先销毁,然后再创建。(state.count变化了)
五,父子组件传值–useContext
这个用法,其实和react-redux差不多了。
具体代码:
import React ,{useState,createContext,useContext}from 'react';
const CountContext=createContext()
function MyComponent() {
let count =useContext(CountContext)
return <h2>{count}</h2>
}
function Example () {
const [count,setCount]=useState(0)
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>setCount(count+1)}>点我</button>
<CountContext.Provider value={count}>
<MyComponent></MyComponent>
</CountContext.Provider>
</div>
);
}
export default Example;
但是实际使用的时候,通常父子组件在不同的地方,于是createContext会独立创建在一个文件中:
六,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:
break;
}
},0)
return (
<div>
<p>点击{count}次</p>
<button onClick={()=>dispatch('add')}>加1</button>
<button onClick={()=>dispatch('sub')}>减1</button>
</div>
);
}
export default ReducerDemo;
七,使用useReducer和useContext实现redux的效果
实际上,可以直接取代redux,更简单一些