react组件有两种写法一种是export default直接暴露一个function,还有一种是直接定义一个class类然后继承react库的Component类这两种方式来创建react组件。
对于class类创建react组件的方式来说可以直接定义组件的this.state,这样在render中return的jsx模板中就可以直接this.state调用,以及this.setState来更新this.state的参数并更新视图。!!!注意:class类创建的组件不能使用hook。
对于function创建react组件的方式不需要继承react库的Component类,而且不能直接通过this.state设置组件中的数据。这时候就需要用到hook了,hook是针对function创建react组件设置state数据使用的。!!!注意:function创建react组件不能使用this.state。
下面直接看代码吧
import React, { useState,useEffect } from 'react';
export default function Hook() {
const [count, setCount] = useState(0);
const [boller, setBoller] = useState(false)
useEffect(() => {
console.log('count')
},[count])
useEffect(() => {
console.log('boller')
},[boller])
return (
<div>
<p> {count} {boller ? 'true' : 'false'} </p>
<button onClick={() => {setCount(count + 1); setBoller(!boller)}}>
点击
</button>
</div>
);
}
hook需要用到react库的useState;定义一个hook数组,数组第一个传入的是state数据的名字,数组第二位是方法用来更新这个hook的数据;useState传入的是该hook的默认值。这样一个hook就定义完成了,点击button按钮调用对应更新hook的方法来改变hook和更新视图。
上面还提到了useEffect这个api,这个api主要是在更新这个hook的数据的方法执行后的一个回调方法可以传入两个参数,第一个参数是一个callback回调函数;第二个参数是对应哪写hook更新后才执行不传为所有hook更新都执行,形式为数组。useEffect有点类似vue中的watch监听。
最近的taro项目里面学到了不少之前react中没有注意到的知识点,果然自学的认知还是比较局限的。估计这次taro的项目做完react就能上手项目了。加油!!!
#2019.9.23
如果useEffect中的第二个参数传入空数组则被视为是类似于componentdidmounted这样的生命周期,如果第一个传入的callback参数return一个方法则视为类似于componentdidUnmounted生命周期函数
useEffect(() => {
console.log('页面首次加载')
return () => {
console.log('页面卸载的事件')
}
},[])
#2020.1.06
这段时间比较有空记录一下之前积累的知识点
除了上面的两个常用的hook之外还有useContext,useReducer,useCallback,useMemo,useRef,useImperativeHandle,useLayoutEffect这几个,虽然比较不常用但是还是要学习下的
useContext:类似redux和mobx全局store的功能
目录结构:
context.js:
import React from 'react'
const MyContext = React.createContext()
export default MyContext
父组件:通过context.js暴露的组件对象创建一个Provider组件并传入value参数(这是给父组件下子组件的共享数据)
import React, {
useState,
useEffect,
useContext,
} from 'react';
import { withRouter } from 'react-router-dom'
import HookApi from './components/hookApi'
import StateContext from './context.js'
function Hookcom (props) {
const [count, setCount] = useState(0);
const [boller, setBoller] = useState(true)
useEffect(() => {
console.log(context)//useContext
}, [])
return (
<div>
<StateContext.Provider value={{
name: count,
changeName: (value) => {
setCount(value)
}
}}>
<HookApi Cref={childRef}>
<HookApi.Con>423423421111111111111111113</HookApi.Con>
<HookApi.Con>23423423423424234</HookApi.Con>
</HookApi>
</StateContext.Provider>
</div>
);
}
export default withRouter(Hookcom)
子组件 :useContext接受一个由React.createContext()返回的组件对象
import React, {
useContext
} from 'react';
import StateContext from '../context.js'
function HookApi(props) {
const ContextState = useContext(StateContext)
return (
<div>
<div
onClick={() => {
ContextState.changeName(123456)
}}>
{ContextState.name}
</div>
</div>
);
}
export default HookApi
useReducer:类似redux通过发布dispatch触发数据更新
import React, {
useReducer
} from 'react';
import store from '../../mobxStore/mobx'
function reducerFn(value, action) {//dispatch为操作
console.log(value, action.type)//value初始值,reducer为结果
switch (action.type) {
case 'increment':
return { num: value.num + 1, name: 12 };
case 'decrement':
return { num: value.num - 1, name: 1112 };
default:
throw new Error();
}
}
function Hookcom(props) {
const [reducer, dispatch] = useReducer(reducerFn, { num: 1, name: 1212 })//传入第一个参数为回调第二个为初始值,对比useState更适合处理较为复杂的数据,useReducer 还能给那些会触发深更新的组件做性能优化
useEffect(() => {
console.log(reducer)//useReducer
}, [])
return (
<div>
<button onClick={() => {
dispatch({ type: 'increment' })
}}>
点击
</button>
</div>
);
}
export default Hookcom
useCallback:在数据更新之后执行的方法
import React, {
useCallback,
useMemo
} from 'react';
import store from '../../mobxStore/mobx'
function countCb() {
console.log('更新了count')
}
const con = React.createContext({ ...store })//useContext
function Hookcom(props) {
const [count, setCount] = useState(0);
useCallback(countCb(), [count])//useCallback在count改变时触发可以避免非必要渲染
useEffect(() => {
console.log(context)//useContext
}, [])
return (
<div>
<button onClick={() => {
setCount(count + 1);
}}>
点击
</button>
</div>
);
}
export default Hookcom
useMemo在count改变时触发可以避免非必要渲染(类似vue的计算属性)
import React, {
useCallback,
useMemo
} from 'react';
import store from '../../mobxStore/mobx'
function countCb() {
console.log('更新了count')
return 1234
}
const con = React.createContext({ ...store })//useContext
function Hookcom(props) {
const [count, setCount] = useState(0);
useCallback(countCb(), [count])//useCallback在count改变时触发可以避免非必要渲染
const newComputedValue = useMemo(() => countCb(), [count]);//useMemo在count改变时触发可以避免非必要渲染(类似vue的计算属性)
useEffect(() => {
console.log(context)//useContext
}, [])
return (
<div>
<button onClick={() => {
setCount(count + 1);
}}>
点击
</button>
{ newComputedValue }
</div>
);
}
export default Hookcom
useRef,useImperativeHandle:这两个放到一起来说,主要是hook进行父子组件间的通信
父组件(useRef)
import React, {
useRef
} from 'react';
function Hookcom(props) {
const childRef = useRef(); //父组件直接调用子组件设置,子组件中使用useImperativeHandle来设置对应要对接通信的数据
useEffect(() => {
console.log(childRef)//useRef
}, [])
return (
<div>
<HookApi Cref={childRef}>
</HookApi>
<button onClick={() => {
childRef.current.handleClick()//触发子组件方法
}}>
点击
</button>
</div>
);
}
export default Hookcom
子组件(useImperativeHandle)
import React, {
useImperativeHandle
} from 'react';
function HookApi(props) {
useImperativeHandle(props.Cref, () => ({//hook写法父组件直接调用子组件方法
handleClick: () => {
console.log('子组件的方法被父组件调用',a)
},
b: 1322342
}))
const [a, setA] = useState(1)
return (
<div>
HookApi
{/* {props.Cref.current.b}//错误写法取不到 */}
</div>
);
}
export default HookApi
useLayoutEffect
import React, {
useLayoutEffect
} from 'react';
function Hookcom(props) {
const [count, setCount] = useState(0);
useLayoutEffect(() => {//和useEffect相同但是尽量使用useEffect
console.log('数据发生变化')
}, [count])
return (
<div>
<button onClick={() => {
setCount(count + 1);
}}>
点击
</button>
</div>
);
}
export default Hookcom