React API 使用demo
· 分享镜#react
https://github.com/Aimee1608/react-api
纯函数组件
function Component(){
return (<div>hello world</div>)
}
类组件
import React from 'react'
class Component extends React.Component{
render(){
return (<div>hello world</div>)
}
}
常规父子组件
// 子组件
import React from 'react'
export default class Child extends React.Component {
render() {
const { count } = this.props
return (
<div>
<h2>child</h2>
<div>count: {count}</div>
</div>
)
}
}
// 父组件
import React from 'react'
import Child from './../Child'
export default class Parent extends React.Component {
state = {
count: 0
}
handleClick() {
this.setState({ count: this.state.count + 1 })
}
render() {
const { count } = this.state
return (
<div>
<h1>Parent</h1>
<button onClick={this.handleClick.bind(this)}>加1</button>
<Child count={count}></Child>
</div>
)
}
}
生命周期
一个组件的生命周期:
挂载时:
- constructor
- static getDerviedStateFromProps
- 接受两个参数 props 和state ,用于处理state中依赖props的值更新,需要返回内容,默认可以返回null
- render
- componetDidMount
更新时:
- static getDerviedStateFromProps
- shouldComponentUpdate
- 接受两个参数,nextProps, nextState 根据参数判断是否需要更新数据,需返回boolean false为不更新,true为更新
- render
- getSnapshotBeforeUpdate
- 接受两个参数 preProps preState 需要返回参数,如果返回null 或者传递给ComponentDidUpdate的值
- 可以在此钩子中获取真实dom更新前的数据信息,比如滚动的位置
- componentDidUpdate
- 接受三个参数,preProps, preState, snapshot, snapshot参数为getSnapshotBeforeUpdate返回的数据
卸载时:
- componentWillUnmount
错误捕获:
- static getDerviedStateFromError
- 接受一个参数,error 用于返回错误信息
- 如果有副作用需要使用componentDidCatch
- 会捕获子组件中的错误
- componentDidCatch
- 接受两个参数,error 和 info 用于记录错误信息
- 错误日志捕获这可以在这里设置
- 会捕获子组件中的错误
// parent
import React from 'react'
export default class Parent extends React.Component {
state = {
hasError: false
}
// static getDerviedStateFromError(error) {
// console.log('getDerviedStateFromError', error)
// return { hasError: true }
// }
componentDidCatch(error, info) {
console.log('componentDidCatch', error, info)
this.setState({ hasError: true })
}
render() {
const { hasError } = this.state
if (hasError) {
// 你可以渲染任何自定义的降级 UI
return <h1>Something went wrong.</h1>
}
return this.props.children
}
}
// child
import React from 'react'
export default class Child extends React.Component {
state = {
error: null
}
handleClick() {
this.setState({
error: new Error('error')
})
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>抛出错误</button>
{this.state.error}
</div>
)
}
}
// middle
import React from 'react'
import Parent from './Parent'
import Child from './Child'
export default class Middle extends React.Component {
render() {
return (
<Parent>
<Child></Child>
</Parent>
)
}
}
父子组件生命周期:
子组件中引用了父组件的数据 父组件更新 父组件卸载
挂载时
- parent constructor
- parent static getDerviedStateFromProp
- parent render
- child constructor
- child static getDerviedStateFromProp
- child render
- child componentDidMount
- parent componentDidMount
更新时:
- parent static getDerviedStateFromProps
- parent shouldComponentUpdate
- parent render
- child static getDerviedStateFromProps
- child shouldComponentUpdate
- child render
- child getSnapshotBeforeUpdate
- parent getSnapshotBeforeUpdate
- child componentDidUpdate
- parent componentDidUpdate
卸载时:
- child componentWillUnmount
- parent componentWillUnmount
高阶组件
- 定义一个函数HigherOrderComponent,接受一个或多个参数,其中包含Component组件类
- 在render中 return Component的信息,组件上可以挂载props数据 和自定义的数据
- 在Demo中 通过调用HigherOrderComponent 函数就可以得到一个已经注入props的组件
// HigherOrderComponent
import React from 'react'
export default function HigherOrderComponent(Component) {
return class extends React.Component {
render() {
return <Component {...this.props} name="hight"></Component>
}
}
}
// Demo
import React from 'react'
import HigherOrderComponent from './HigherOrderComponent'
class Demo extends React.Component {
render() {
const { name, count } = this.props
return (
<div>
高阶组件返回的信息:{name} {count}
</div>
)
}
}
export default HigherOrderComponent(Demo)
// Parent
import Demo from './Demo'
import React from 'react'
export default class Index extends React.Component {
render() {
return <Demo count={5}></Demo>
}
}
context上下文
主要解决层级嵌套太深的props传递
简易使用
- 由React.createContext()创建 context
- context 中包含Consumer 和Provider
- Provider为提供方 有一个value属性 接受的是需要提供的数据
- Consumer是 接受使用方,接受一个函数,函数参数为value
- 定义自己的组件直接使用Context
import React from 'react'
const Context = React.createContext()
class Button extends React.Component {
render() {
return <Context.Consumer>{value => <div>context-info:{value}</div>}</Context.Consumer>
}
}
export default class Container extends React.Component {
render() {
return (
<Context.Provider value="contxt">
<Button></Button>
</Context.Provider>
)
}
}
封装通用版的context
- 创建context
- 创建connectStore函数,返回一个新的组件,组装Consumer 将Context 的值注入到Component上
- 常规组件如果需要使用context 只需要,调用connectStore 返回一个新的Component
- 在根父组件注入Provider,无论多少层子组件中如果需要使用context的,可以通过connectStore来获取
import React from 'react'
// 创建context
const context = React.createContext()
// 生成Consumer 供使用方使用
const Consumer = context.Consumer
const Provider = context.Provider
// 组装Consumer 将Context 的值注入到Component上
function connectStore(Component) {
return class extends React.Component {
render() {
return <Consumer>{value => <Component {...value} {...this.props}></Component>}</Consumer>
}
}
}
// 常规的组件定义
class Demo extends React.Component {
render() {
const { contextInfo, propsInfo } = this.props
return (
<div>
demo1--顶层-connectStore拿到的信息:{contextInfo}; 父组件拿到的Info:{propsInfo}
</div>
)
}
}
// 生成组装后的组件
const NewDemo = connectStore(Demo)
class Demo2 extends React.Component {
render() {
const { contextInfo, propsInfo } = this.props
return (
<div>
demo2--嵌套多层-connectStore拿到的信息:{contextInfo}; 父组件拿到的Info:{propsInfo}
</div>
)
}
}
const NewDemo2 = connectStore(Demo2)
// 在父组件中使用
class Parent1 extends React.Component {
render() {
return (
<div>
<h5>parent1:</h5>
{this.props.children}
</div>
)
}
}
class Parent2 extends React.Component {
render() {
return (
<div>
<h5>parent2:</h5>
<NewDemo2 propsInfo="嵌套的propsInfo"></NewDemo2>
</div>
)
}
}
export default class Parent extends React.Component {
render() {
return (
<Provider value={{ contextInfo: 'contextInfo' }}>
<NewDemo propsInfo="等层的propsInfo"></NewDemo>
<Parent1>
<Parent2></Parent2>
</Parent1>
</Provider>
)
}
}
多个context
import { render } from 'less'
import React from 'react'
const contextRed = React.createContext('red')
const contextBlue = React.createContext('blue')
class Child extends React.Component {
render() {
return (
<contextRed.Consumer>
{red => (
<contextBlue.Consumer>
{blue => (
<div>
<h5>多个context</h5>
<div>第一个:{red}</div>
<div>第二个:{blue}</div>
</div>
)}
</contextBlue.Consumer>
)}
</contextRed.Consumer>
)
}
}
export default class Conent extends React.Component {
render() {
return (
<contextRed.Provider value="red">
<contextBlue.Provider value="blue">
<Child />
</contextBlue.Provider>
</contextRed.Provider>
)
}
}
contextType
简化Consumer的操作,直接引入context 并设置就可以使用
- 在使用方 设置static contextType 可在组件全局使用context
import React from 'react'
const context = React.createContext()
class Child extends React.Component {
static contextType = context
render() {
const { name } = this.context
return (
<div>
<h5>contextType</h5>
<div>获取的值: {name}</div>
</div>
)
}
}
class Middle extends React.Component {
render() {
return <Child></Child>
}
}
export default class Content extends React.Component {
render() {
return (
<context.Provider value={{ name: 'contextType' }}>
<Middle></Middle>
</context.Provider>
)
}
}
React.PureComponent
- 会默认添加shouldComponentUpdate生命钩子,对pros和state进行浅比较,如果没有改变则返回false,阻止组件的render
import React from 'react'
export default class Demo extends React.PureComponent {
componentDidUpdate() {
console.log('PureComponent--demo------componentDidUpdate')
}
render() {
return <div>PureComponent--demo</div>
}
}
React.memo()
- update更新的时候,不会渲染多次
import React from 'react'
function Pure() {
console.log('Pure----render')
return <div>纯函数组件</div>
}
export default React.memo(Pure)
React.createRef()
- 定义一个属性myRef 设置的值为React.createRef()创建的ref
- 通过在render 中的dom元素上 ref属性中设置this.myRef来设置值
import React from 'react'
export default class CreateRef extends React.Component {
constructor(props) {
super(props)
}
myRef = React.createRef()
componentDidMount() {
console.log('React.createRef------->', this.myRef)
}
render() {
return (
<div>
<h2>React.createRef()</h2>
<div ref={this.myRef}>这个demo</div>
</div>
)
}
}
React.forwardRef()
- 父组件获取到子组件中的dom
import React from 'react'
class MChild extends React.Component {
render() {
return <input ref={this.props.childRef} type="text" />
}
}
const Child = React.forwardRef((props, ref) => <MChild {...props} childRef={ref}></MChild>)
export default class Parent extends React.Component {
childRef = React.createRef()
handle() {
this.childRef.current.focus()
}
render() {
return (
<div>
<h2>React.forwardRef</h2>
<div>
<Child ref={this.childRef}></Child>
<button onClick={this.handle.bind(this)}>聚焦child</button>
</div>
</div>
)
}
}
hooks 的使用
16.8更新后支持
纯函数组件
- 没有state状态
function Pure() {
return <div>纯函数组件</div>
}
export default Pure
useState
- useState接受默认参数,返回一个数组,数组第一个值为定义的变量名,第二个值为修改变量的方法
- 修改state的值时,需要哦通过返回的set方法来设置
- 需要在函数体顶部定义
import React, { useState } from 'react'
export default function UseState() {
const [count, setCount] = useState(0)
return (
<div>
<h5>useState</h5>
<div>
count:{count} <button onClick={() => setCount(count + 1)}>增加</button>
</div>
</div>
)
}
useEffect
副作用hook, 包含了 componentDidMount componentDidUpdate componentWillUnmount
- 可以返回一个函数,用于消除副作用,类似componentWillUnmount时机调用
- 可以调用多个useEffect
- 可以传递一个值控制是否执行
- 如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])
import { useState, useEffect } from 'react'
export default function UseEffect() {
const [count, setCount] = useState(0)
const [name, setName] = useState('useEffect')
useEffect(() => {
document.title = 'useEffect' + count
console.log('useEffect----->')
})
// 调用多个
useEffect(() => {
console.log('useEffect----->1')
})
useEffect(() => {
console.log('useEffect----->2')
})
// 返回函数用于清除副作用
useEffect(() => {
console.log('useEffect-----> return ')
return () => {
console.log('unmount')
}
})
useEffect(() => {
console.log('useEffect-----> name 更新了 ', count)
}, [name]) // 仅在 count 更改时更新
useEffect(() => {
console.log('useEffect----->[]')
}, [])
return (
<div>
<h5>useEffect</h5>
<div>
count:{count} <button onClick={() => setCount(count + 1)}>增加</button>
</div>
<div>
name :{name}修改:<button onClick={() => setName('updated')}>修改</button>
</div>
</div>
)
}
useContext
- 对于函数式组件,可以使用useContext 来使用context,使用简单方便
import React from 'react'
const ThemeContext = React.createContext()
const obj = { name: 'useContext' }
function Demo() {
return (
<div>
<Demo2 />
</div>
)
}
function Demo2() {
const context = React.useContext(ThemeContext)
return (
<div>
<h2>useContext</h2>
<div>contextinfo: {context.name}</div>
</div>
)
}
export default function UseContext() {
return (
<ThemeContext.Provider value={obj}>
<Demo />
</ThemeContext.Provider>
)
}
useRef
- 用于在函数式组件中获取dom元素
import React from 'react'
export default function UseRef() {
const ref = React.useRef()
const onHandle = () => {
ref.current.focus()
}
return (
<div>
<h2>useRef</h2>
<input ref={ref} type="text" />
<button onClick={onHandle}>点击通过ref聚焦</button>
</div>
)
}
useReducer
- 和redux类似
- 加强版的useState, 可以自定义复杂的数据操作
import React, { useReducer } from 'react'
function init(initialCount) {
return { count: initialCount }
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
case 'reset':
return init(action.payload)
default:
throw new Error()
}
}
export default function Counter() {
const [state, dispatch] = useReducer(reducer, 1, init)
return (
<div>
<h2>useReducer</h2>
count: {state.count}
<button onClick={() => dispatch({ type: 'reset', payload: 1 })}>reset</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
)
}
useMemo
- 可以使用useMemo设置缓存数据,有点类似vue里面的computed
- useMemo函数的第一个函数参数,可以用于复杂的计算
import React, { useState, useMemo } from 'react'
function Child(props) {
const userInfo = useMemo(() => {
console.log('child----useMemo')
return {
name: props.name
}
}, [props.name])
return <div>child: {userInfo.name}</div>
}
export default function Parent() {
const [name, setName] = useState('')
const [count, setCount] = useState(0)
return (
<div>
<h2>useMemo</h2>
<div>
<Child name={name}></Child>
<button onClick={() => setName('parent--useMemo')}>设置</button>
</div>
<div>
count:{count}
<button onClick={() => setCount(count + 1)}>设置</button>
</div>
</div>
)
}
useCallback
- 和useMemo有点类似,只有依赖改变,才会执行的第一个参数函数,而useMemo是使用的第一个参数返回的结果
- useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
- 一般用于事件的绑定
import React, { useCallback, useState } from 'react'
export default function UseCallback() {
const [count, setCount] = useState(0)
const [name, setName] = useState('hah')
const add = () => {
setCount(count + 1)
}
const changeName = useCallback(() => {
// 只有count变化后,该函数才执行,否则不执行
setName(name + 'changed')
}, [count])
return (
<div>
<h2>useCallback</h2>
<div>
count:{count}
name:{name}
<button onClick={add}>加</button>
<button onClick={changeName}>设置name</button>
</div>
</div>
)
}
useImperativeHandle
- 暴露ref,可以供父组件使用
import React, { useImperativeHandle, useRef } from 'react'
const Child = React.forwardRef((props, ref) => {
const inputRef = useRef()
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
}
}))
return <input ref={inputRef} type="text" />
})
export default function Parent() {
const childRef = useRef()
return (
<div>
<h2>useImperativeHandle</h2>
<Child ref={childRef}></Child>
<button onClick={() => childRef.current.focus()}>聚焦</button>
</div>
)
}
useLayoutEffect
- 在页面渲染之前更新
import { useLayoutEffect, useEffect, useState } from 'react'
export default function UseLayoutEffect() {
const [count, setCount] = useState(0)
// 使用useEffect 会产生二次渲染
// useEffect(() => {
// if (count === 0) {
// setCount(10 + Math.random() * 200)
// }
// }, [count])
// 不会产生二次渲染
useLayoutEffect(() => {
if (count === 0) {
setCount(10 + Math.random() * 200)
}
}, [count])
return (
<div>
<h2>useLayoutEffect</h2>
<div>uselayouteffect: {count}</div>
<button onClick={() => setCount(0)}>+</button>
</div>
)
}
useDebugValue
- 调试工具使用的
useDebugValue(count ? 'Online' : 'Offline')
自定义hooks
import { useState, useEffect } from 'react'
function useMyHooks(props) {
const [value, setValue] = useState(props)
useEffect(() => {
console.log('useEffect----->useMyHooks')
setValue(6)
})
return value
}
export default function MyHooks() {
const value = useMyHooks(9)
const [count, setCount] = useState(0)
return (
<div>
<h5>自定义hooks</h5>
<div>
count:{count}获取的值: {value}
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
</div>
)
}
使用规则
- 只在函数顶部使用
- 只在React函数组件中使用
- 不要在条件语句中调用hook
Portals
Portals 提供了一种一流的方式来将子组件渲染到存在于父组件的 DOM 层次结构之外的 DOM 节点中。结构不受外界的控制的情况下就可以使用portals进行创建
ReactDom.createPortal()
- 可以在根节点外挂载到指定节点
- 常见的有model模态框
import React from 'react'
import ReactDom from 'react-dom'
const model = document.getElementById('model')
class CreatePortal extends React.Component {
constructor(props) {
super(props)
this.el = document.createElement('div')
}
componentDidMount() {
model.appendChild(this.el)
}
componentWillUnmount() {
model.removeChild(this.el)
}
render() {
return ReactDom.createPortal(this.props.children, this.el)
}
}
export default class Demo extends React.Component {
render() {
return (
<div>
<h2>React.createPortal()</h2>
<CreatePortal>
<div>内容</div>
</CreatePortal>
</div>
)
}
}
事件冒泡
在 #app-root 里的 Parent 组件能够捕获到未被捕获的从兄弟节点 #modal-root 冒泡上来的事件。
import React from 'react'
import ReactDom from 'react-dom'
const model = document.getElementById('model')
class CreatePortal extends React.Component {
constructor(props) {
super(props)
this.el = document.createElement('div')
}
componentDidMount() {
model.appendChild(this.el)
}
componentWillUnmount() {
model.removeChild(this.el)
}
render() {
return ReactDom.createPortal(this.props.children, this.el)
}
}
function Child() {
// 这个按钮的点击事件会冒泡到父元素
// 因为这里没有定义 'onClick' 属性,定义了只要不拦截,也会冒泡到父组件
return (
<div className="modal">
<button onClick={() => console.log('portals')}>Click</button>
</div>
)
}
export default class Demo extends React.Component {
state = { clicks: 0 }
handleClick() {
// 当子元素里的按钮被点击时,
// 这个将会被触发更新父元素的 state,
// 即使这个按钮在 DOM 中不是直接关联的后代
this.setState(state => ({
clicks: state.clicks + 1
}))
}
render() {
return (
<div onClick={this.handleClick.bind(this)}>
<h2>React.createPortal()</h2>
<p>Number of clicks: {this.state.clicks}</p>
<CreatePortal>
<Child></Child>
</CreatePortal>
</div>
)
}
}
Profiler
用于计算渲染时长,用于辅助定位页面性能问题
评论(0)
登录后参与评论。
还没有评论,来抢沙发吧。

