先从最常用的useState开始。
import React, { useState, useMemo } from 'react';
const Count = () => {
/**
* const [state, setState] = useState(initState)
* usetState(initState)接收一个参数作为state的初始值,返回state值和设置(改变)state的函数setState
*/
const [count, setCount] = useState(0)
const [clickTimes, setClickTimes] = useState(0)
let log = `count:${count},clickTime:${clickTimes}` //每点击一次,log都会发生变化
return (
<div>
<p>{log}</p>
<button onClick={() => {
setCount(count+1)
setClickTimes(clickTimes+1)
} }>count加一</button>
<button onClick={() => {
setCount(count-1)
setClickTimes(clickTimes+1)
}}>count减一</button>
<button onClick={() => {
setCount(count)
setClickTimes(clickTimes+1)
}}>count不变</button>
</div>
)
}
export default Count
上面是setState的基本用法。现在如果有一个新需求,就是只有在变量count发生变化的时候,变量log才发生变化,那么就引出了useMemo。
import React, { useState, useMemo } from 'react';
const Count = () => {
...
let log = useMemo(() => {
return `count:${count},clickTime:${clickTimes}`
},[count])
...
}
再来一个新的需求,在每次count发生变化之后,每隔count秒,输出一次log。这就引出引出下一个hookuseEffect。
import React, { useState, useMemo, useEffect } from 'react';
const Count = () => {
...
useEffect(() => {
let timer = setInterval(() => {
console.log(`每${count}秒,打印一次`)
}, 1000*count);
return () => {
clearInterval(timer)//执行清除定时器操作,类似于componentWillUnmount
}
},[count])//只有在count发生变化的时候才会执行useEffect
...
}
在接下来看一看useContext,直接看官方文档给出的示例:
import React, { useContext } from 'react';
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
而如果不使用useContext,可以这样:
...
class ThemedButton extends React.Component{
static contextType = ThemeContext
render(){
let theme = this.context
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
}
...
或者可以这样:
function ThemedButton() {
return (
<ThemeContext.Consumer>
{
theme => (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
)
}
</ThemeContext.Consumer>
);
}
接下来是useReducer,结合Provider和useContext,可以有替代redux的效果:
import React,{useReducer, useContext, useMemo} from 'react'
function init(initUserList){
return {usersList:initUserList}
}
let reducer = function(state, action){
console.log(state, action)
switch (action.type){
case 'changeName':
let usersList = state.usersList.map(item => {
if(item.id === action.payload.id){
item.userName = action.payload.newValue
}
return item
})
return {usersList}
default:
throw new Error()
}
}
let UsersContext = React.createContext({usersList:[],dispatch:function(){}})
let Page = function({initUserList}) {
const [state, dispatch] = useReducer(reducer, initUserList, init)
return (
<UsersContext.Provider value={{usersList:state.usersList,dispatch:dispatch}}>
<Parent>
</Parent>
</UsersContext.Provider>
)
}
let Parent = function(){
return (
<div>
<UsersList></UsersList>
</div>
)
}
let UsersList = function(){
let {usersList,dispatch} = useContext(UsersContext)
return (
<ul>
{
usersList && usersList.map(item => {
let {userName, userAge, id} = item
return (
<li key={id}>
<input type="text" onChange={(event) => dispatch({type:'changeName',payload:{id,newValue:event.target.value}})} value={userName}/>
<span>userAge:{userAge}</span>
<span>id:{id}</span>
</li>
)
})
}
</ul>
)
}
let WrapperPage = function(){
let initUserList = [
{userName:'jack', userAge:10, id:0},
{userName:'tom', userAge:12, id:1},
{userName:'suna', userAge:13, id:2},
]
return (
<Page initUserList={initUserList}></Page>
)
}
export default WrapperPage
算了,懒得写了,就写到这里...