React入门useState,useRef,useContent等API讲解

useState


语法:
const [n, setN] = React.useState(0);

0是n的默认值,setN是操作n的函数

setN: setN(i=>i+1)

  1. 我们以为setN会改变n,但是事实往往出乎意料,n并不会变,他是将改变后的数据存到一个数据里面(具体在哪里我们先定为x),而不是直接赋值去改变n
  2. setN一定会触发组件的重新渲染

useState:

  1. useState肯定会从x那里,读取到n的最新值

x:

  1. 每个组件都有自己的x,这个x我们命名为state

useRef


1.如果你需要一个值,在组件不断render的时候保持不变

// 在组件不断render的时候,count的值变了,但是页面显示不变
// 每次创建的是新的count,而不是用上一次的count
  const count = useRef(0)
    const onClick = () => {
    count.current += 1
    console.log(count)
  }

React入门useState,useRef,useContent等API讲解_第1张图片
2.如果你想要改变这个值

  // 每次页面也会发生变化,展示对应的值
  const [_, set_] = useState(null)
  const count = useRef(0)
  const onClick = () => {
    count.current += 1
    set_(Math.random())
    console.log(count)
  }

React入门useState,useRef,useContent等API讲解_第2张图片
3.假设我们有这样一个需求,记录点击按钮的次数

// 使用useRef记录改变n多少次
const count = useRef(0)
useEffect(() => {
    count.current += 1
    console.log(count)
})

React入门useState,useRef,useContent等API讲解_第3张图片

useContext


const themeContext = React.createContext(null);

function App() {
  const [theme, setTheme] = React.useState("red");
  return (
    // themeContext.Provider 创建一个局部作用域
    // 其中里面的所有组件都可以使用setTheme这个函数
    
      

{theme}

); } function ChildA() { // ChildA这个子组件内部想使用父组件setTheme函数的方式 const { setTheme } = React.useContext(themeContext); return (
); }

useReducer


创建初始值

const store = {
  user: null,
  books: null,
  movies: null,
}

创建所有操作的reducer

function reducer(state, action) {
  switch (action.type) {
    case 'setUser':
      return { ...state, user: action.user }
    case 'setBooks':
      return { ...state, books: action.books }
    case "setMovies":
      return { ...state, movies: action.movies }
    default:
      throw new Error();
  }
}

使用React提供的createContext创建Context

// 使用React提供的createContext API,将子组件套住
const Context = createContext(null);

function App() {
  return (
    // 套住子组件
    
        
        
); } // 子组件User function User() { return (

个人信息

) }

创建对数据读写的API

function App() {
  // 使用useReducer对数据进行读写操作
  const [state, dispatch] = useReducer(reducer, store)
  return (
    // 套住子组件 value是将读和写的API赋值给子组件
    
      
      
); }

子组件中使用useContext读取数据

function User() {
  // 子组件中使用父组件数据的方式
  const { state, dispatch } = useContext(Context)
  // 使用useEffect,只在初次进入的时候才会发起请求
  // 避免每次render的时候都会请求
  // dispatch会改写初始化的数据
  useEffect(() => {
    ajax("/user").then(user => {
      dispatch({ type: 'setUser', user })
    });
  }, []);
  return (
    

个人信息

name: {state.user ? state.user.name : ""}
) }

useEffect(render之后执行)


1.当useEffect,第二个参数为空数组时

  // 第一个参数是执行函数
  // 第二个参数如果是个空数组,只会在第一次render之后执行一次
  // 后面再次render也不会执行
  useEffect(() => {
    console.log('第一次render之后执行!')
  }, [])

2.当useEffect,第二个参数不传时

  // 第一个参数是执行函数
  // 第二个参数不传, 后面每次render都会执行
  useEffect(() => {
    console.log('每次render之后执行!')
  })

2.当useEffect,第二个参数传需要变化的值时

  // 第一个参数是执行函数
  // 第二个参数传需要改变的值的时候(要放在数组里)
  // 当n变化了,函数才会执行
  useEffect(() => {
    console.log('每次render之后执行!')
  }, [n])

useLayoutEffect(DOM完毕之后,render之前执行)


使用的方式和useEffect一样,时间顺序不一样

memo


看下面这个图:

  1. 当我每次点击按钮的时候,Child函数组件都会执行
  2. 但是Child并没用用到n这个值

React入门useState,useRef,useContent等API讲解_第4张图片

  1. 用memo封装一下,n的值在改变的时候,Child函数组件就不会执行了
  2. 只有m变化的时候才执行

React入门useState,useRef,useContent等API讲解_第5张图片

  1. 有问题,当我们给子组件传递函数的时候,我们点击按钮
  2. Child函数组件还是执行了

React入门useState,useRef,useContent等API讲解_第6张图片
如何解决这样的问题?用到下面的API

useMemo


  1. 将传递给子组件的函数,放在useMemo中,第二个参数是要改变的值m
  2. 这样就只有当m改变的时候,Child函数组件才会重新执行了

React入门useState,useRef,useContent等API讲解_第7张图片

  1. 是不是觉得useMemo很别扭,因为他里面是函数作为参数,返回的还是一个函数,另一个API可以解决这样的问题: useCallback
  2. useCallback和useMemo是一样的
  const onClickChild = useCallback(() => {
    console.log(m)
  }, [m])

forwardRef


  1. 在函数式的组件中是无法使用ref获取子组件的
  2. 想要获取子组件使用forwardRef这个API
  3. 将子组件Button2用forwardRef包裹起来
  4. 这样就能获取到button的DOM
function App() {
  const buttonRef = useRef(null)
  return (
    
按钮
); } function Button2(props, ref) { console.log(props) console.log(ref) return ( ); } const Button3 = React.forwardRef(Button2)

React入门useState,useRef,useContent等API讲解_第8张图片

自定义Hook


用一段代码来表示他的NB之处,下面这段代码useList是封装在了另一个文件里面

  1. 假设./hooks/useList这个文件里面是对list的增,删,改,查
import useList from "./hooks/useList"
function App() {
  const { list, setList } = useList()
  return (
    

List

{list ? (
    {list.map(item => (
  1. {item.name}
  2. ))}
) : ("加载中.....")}
); }
  1. 这个是./hooks/useList这个文件内部
  2. 这个文件只有一个假的ajax
  3. 还可以将增,改,删等操作封装进去,这就会将操作和展示分开
  4. 模块化会使代码格外清晰,这就是他的NB之处
import {
    useState,
    useEffect
} from "react"

const useList = () => {
    const [list,
        setList
    ] = useState(null)
    useEffect(() => {
        ajax("/list").then(list => {
            setList(list)
        })
    }, [])
    return {
        list,
        setList
    }
}
export default useList;

function ajax(n) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve([{
                id: 1,
                name: "Frank"
            }, {
                id: 2,
                name: "Sun"
            }, {
                id: 3,
                name: "Jack"
            }])
        }, 2000)
    })
}

你可能感兴趣的:(react.js,hook)