React Hooks

JSX语法:

JSX将HTML语法直接加入到JS代码中,在通过翻译器转换到纯js后由浏览器执行,实际开发中,JSX在产品打包阶段已经编译为js,无副作用,让代码易于维护更加直观,编译过程由Babel的JSX编译器实现。

类组件开发

import React from 'react'
import Child from './components/Child'
 
export default class Demo extends React.Component{
    state={
        info:{} //传递给子组件
    }
 
    saveList(list){
        //子组件传来的数据
        console.log(list)
    }
    render(){
        <div>
            <Child info={this.state.info} saveList={this.saveList}/>
        </div>
    }
}

函数式组件开发

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

hooks(react 16.8版本以后才支持)

高阶组件为了复用,导致代码层级复杂,生命周期复杂,写成function组件,无状态组件,写成class类组件,成本过高,我们可以使用react hooks

useState(保存组件状态)

const [state,setState] = useState(inintialState)

示例: 

import { useState } from 'react';

function App() {
  const [name, setName] = useState('张三')
  const [text, setText] = useState('')
  const [list, setList] = useState([])
  const [age, setAge] = useState(88)

  function addList() {
    setList([...list, text])
    setText('')
  }
  function handleChange(e) {
    setText(e.target.value)
  }
  function handleDelete(index) {
    console.log(index);
    let arr = [...list]
    arr.splice(index, 1)
    console.log(arr);
    setList(arr)
  }
  return (
    <div className="App">
      app-{name}
      app-{age}
      <button onClick={() => { setName('李四'); setAge(100) }}>改名</button>
      <div>
        <input onChange={e => handleChange(e)} value={text} />
        <button onClick={() => { addList() }}>添加</button>
      </div>
      <ul>{
        list.map((el, index) => {
          return <li key={index}>{el}<button onClick={() => handleDelete(index)}>删除</button></li>
        })
      }</ul>
      {!list.length && <div>暂无事项</div>}
    </div>
  );
}

export default App;

useEffect(处理副作用)和useLayoutEffect(同步执行副作用)

第二个参数为空数组时,此函数只执行一次,相当于 componentDidMount 生命周期函数

import { useState,useEffect } from 'react';

function App() {
  const [list, setList] = useState([])
  useEffect(()=>{
    setList([11])
  },[])
  return (
    <div className="App">
      <ul>{
        list.map((el, index) => {
          return <li key={index}>{el}</li>
        })
      }</ul>
    </div>
  );
}

export default App;

第二个参数传入参数时,此函数会监听该参数的变化,且再次执行该函数,相当于 componentDidUpdate 生命周期函数

import { useState,useEffect } from 'react';

function App(props) {
  const [name, setName] = useState("apple")
  useEffect(()=>{
    setName(name.toUpperCase())
  },[name])
  return (
    <div className="App">
      app-{name}
      <button onClick={()=>{
        setName('orange')
      }}>修改</button>
    </div>
  );
}

export default App;

在useEffect函数内部返回一个函数,在这个函数内里写的逻辑就等同于写在生命周期componentWillUnMount

import { useState,useEffect } from 'react';

function App(props) {
  const [name, setName] = useState("apple")
  useEffect(()=>{
    setName(name.toUpperCase())
    return ()=>{
      console.log('componentWillUnMount')
    }
  },[name])
  return (
    <div className="App">
      app-{name}
      <button onClick={()=>{
        setName('orange')
      }}>修改</button>
    </div>
  );
}

export default App;

useEffect和useLayoutEffect用法基本一致,唯一不同点就是调用时机不同,useLayoutEffect和原来 componentDidMount componentDidUpdate一致,react完成dom后马上同步调用的代码,会阻塞页面渲染,useEffect会再页面渲染完成后才调用。

useCallback(记忆函数)

防止因为组件重新渲染,导致方法被重新创建,起到缓存作用,只有第二个参数发生变化了,才重新声明一次。(因为每次调用useState中的set函数就会触发组件渲染)

在函数内用到的所有变量,需要写在第二个参数数组中,可以监听到变化渲染师重新生成新的函数,如果不写,那么永远都是不会重新生成新的函数,并且使用到的变量值都是旧的,不会更新。

import { useState, useEffect, useCallback } from 'react';

function App() {
  let [name, setname] = useState(0)
  const handleChange = useCallback(() => {
    setname(name + 1);
  }, [name])
  return (
    <div className="App">
      app-{name}
      <button onClick={() => {
        handleChange()
      }}>add</button>
    </div>
  );
}

export default App;

useMemo记忆组件

useCallback的功能完全可以由useMemo所取代,如果你想通过使用useMemo返回一个记忆函数也是完全可以的。

useCallback(fn,inputs)
useMemo(()=>fn,inputs)

唯一区别是:useCallback不会执行第一个参数函数,而是将它返回给你,而useMemo会执行第一个函数并且将函数执行结果返回给你。

所以useCallback常用于记忆事件函数,生成级以后得事件传给子组件使用;而useMemo更适合经过函数计算得到一个确定的值,比如记忆组件。类似于vue中的computed计算属性

import { useState, useEffect, useCallback, useMemo } from 'react';

function App() {
  let [name, setname] = useState(0)
  const name2 = useMemo(() => name+1000, [name])
  const handleChange = useCallback(() => {
    setname(name + 1);
  }, [name])
  return (
    <div className="App">
      app-{name}
      <p>{name2}</p>
      <button onClick={() => {
        handleChange()
      }}>add</button>
    </div>
  );
}

export default App;

useRef(保存引用值)

1.能够用来定位元素或者组件

2.能够存储变量

import { useRef, useState } from 'react';

function App() {
  let [count,setCount] = useState(0)
  const myName = useRef()
  const myCount = useRef(0)
  return (
    <div className="App">
      app
      <input ref={myName}/>
      <p>{myCount.current}</p>
      <button onClick={()=>{
        console.log(myName.current.value)
        myName.current.value = null
        setCount(count+1) //会触发重新渲染
        myCount.current++
      }}>清空</button>
    </div>
  );
}

export default App;

useContext(减少组件层级)

import React,{useContext, useState, createContext} from 'react';

const CountContext = createContext();//创建Context对象
const TestContext = () =>{
    const [count, setCount] = useState(0);
    console.log(CountContext);
    console.log(useContext(CountContext));
    return(
      <div>
          <p>父组件点击次数:{count}</p>
          <button type={"primary"} onClick={()=>setCount(count+1)}>点击+1</button>
          <CountContext.Provider value={count}>
            <Counter/>
          </CountContext.Provider>
      </div>
  )
};
 
const Counter = () => {
    const count = useContext(CountContext);
    console.log(CountContext);
    // console.log(count);
    // console.log(useContext(CountContext));
    return (
        <div>
            <p>子组件获得的点击数量:{count}</p>
        </div>
    );
};
 
export default TestContext;

useReducer

redux的钩子函数,状态数据管理,可以在APP.js中定义一次,在其他组件中传入state, dispatch,进行调用

import { useReducer } from 'react';
//处理函数
const reducer = (preState, action) => {
  let newState = {...preState}

  switch (action.type) {
    case 'add':
      newState.count++
      return newState
    case 'minus':
      newState.count--
      return newState
    default:
      return preState
  }
}

const initialState = {
  count: 0
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState)

  return (
    <div className="App">
      <button onClick={() => {
        dispatch({
          type: 'minus'
        })
      }
      }>-</button>
      {state.count}
      <button onClick={() => {
        dispatch({
          type: 'add'
        })
      }

      }>+</button>

    </div>
  );
}

export default App;

可搭配useContext使用

import { useReducer, createContext, useContext } from 'react';
//处理函数
const reducer = (preState, action) => {
  let newState = { ...preState }

  switch (action.type) {
    case 'add':
      newState.count++
      return newState
    case 'minus':
      newState.count--
      return newState
    default:
      return preState
  }
}

const initialState = {
  count: 0
}
const CountContext = createContext()

function App() {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <CountContext.Provider value={{state,dispatch}}>
      <div className="App">
        <Child1 />
        <Child2 />
      </div>
    </CountContext.Provider>
  );
}

function Child1() {
  const obj = useContext(CountContext)
  return <div>child1-{obj.state.count}
  <button onClick={()=>{
    obj.dispatch({
      type:'minus'
    })
  }}>-</button></div>
}
function Child2() {
  const obj = useContext(CountContext)

  return <div>
  child1-{obj.state.count}
  <button onClick={()=>{
    obj.dispatch({
      type:'add'
    })
  }}>+</button>
  </div>
}
export default App;

  useId

useId 是一个 React Hook,可以生成传递给无障碍属性的唯一 ID。

const id = useId()

 自定义hooks

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中

必须以 use 开头,如不遵循,由于无法判断某个函数是否包含对其内部hook的调用,React将无法自动检查你的hook是否违反了hook规则,与vue3中自定义组合式api用法相同。

import { useState,useEffect } from 'react';

function useList(){
  const [list, setList] = useState([])
  useEffect(()=>{
    setList([11])
  },[])
  return{
    list
  }
}
function App() {
  const {list} = useList()
  return (
    <div className="App">
      <ul>{
        list.map((el, index) => {
          return <li key={index}>{el}</li>
        })
      }</ul>
    </div>
  );
}

export default App;

参考文档:内置 React Hook – React 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Goat恶霸詹姆斯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值