React入门之ReactHooks基本使用

Posted 安之ccy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React入门之ReactHooks基本使用相关的知识,希望对你有一定的参考价值。

前言

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

       如果使用脚手架创建项目,即npx create-react-app + 项目名,生成的主组件App.js默认是函数组件。在之前的案例中,每次我都把它手动改成类组件,因为我需要使用state管理数据(函数组件不能直接使用state)。但如果我使用ReactHooks,就不需要特意将函数组件改成类组件,因为ReactHooks——

  • 提供了useState来完成类似state管理数据的功能;
  • 提供了useContext来管理上下文,功能类似之前写的Context;
  • 提供了useEffect,功能类似类组件的生命周期中挂载、更新、卸载完成之后的三个钩子函数
  • 提供了useReducer,统一管理action,功能就像之前写的redux&reducer

接下来,我们就通过案例来简单了解一下这几个方法的使用



useState的使用

useState是一个函数,传入初始化的数据,返回两个值,分别是:

  1. 数据本身
  2. 更新数据的方法:set-数据

就像这样:

const [books, setBooks] = useState([
     title: '我们仨', id: 1 ,
     title: '我的阿勒泰', id: 2 ,
     title: '蒋勋说《红楼梦》', id: 3 
])

然后我们就可以使用books来获取数据,使用setBooks来更新数据

    // 使用setBooks更新数据,即增加书目
    // params:title 书名
    const addBook = (title)=>
        setBooks([...books,title, id:uuidv4()])
    
    return (
        <div>
            /* 展示数据:书目 */
            <ul>
                books.map(book => 
                    return (
                        <li className='title' key=book.id>book.title</li>
                    )
                )
            </ul>
            /* 将更新书目的方法传递给子组件,让子组件执行 */
            <AddBook addBook=addBook />
        </div>
    )

由子组件辅助完成更新数据的操作:

import React,  useState  from 'react' // 引入必要的库

// 添加新书目
// 接收addBook方法
const AddBook = (addBook) => 
    // 初始化title为空,即用户还未输入想要增加的书目
    const [ title, setTitle ] = useState('');

    // 提交时,调用addBook方法,把新增的title返回
    const handleSubmit = (e)=>
        e.preventDefault();
        addBook(title);
        setTitle("");
    
    return (
        // 用户输入书名并提交
        <form onSubmit=handleSubmit>
            <input type="text" placeholder='书名'
                onChange=(e) => setTitle(e.target.value) value=title />
            <input type='submit' placeholder='添加书目' />
        </form>
    )

效果:

蓝色背景就是我们初始化时写入的数据;
从文本框输入的文字,通过提交,更新到state,并展示出来


useEffect的使用

之前我们谈到React的生命周期,里面有三个比较常用的钩子函数,分别是:

  • componentDidMount():会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方
     
  • componentDidUpdate():会在更新后会被立即调用。首次渲染不会执行此方法。
     
  • componentWillUnmount():会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。


但函数组件没有生命周期,如果想要在页面渲染或更新时执行某些操作,可以使用Hooks的useEffect来完成

下面是一个小例子:

当页面加载或重新渲染(数据更新)时,打印出提示语

引入:

import React,  useState, useEffect  from 'react'

使用:

    // 当页面加载或重新渲染时,打印提示语
    useEffect(()=>
        console.log("useEffect正在执行中。。。")
    )

效果:

当页面刷新时,打印一次;
当添加了书目时,又打印了一次:




不论是哪个数据更新,都会触发useEffect的执行。如果希望useEffect只追踪某几个变量的变化,可以在useEffect的第二个参数中,传入一个数组;当数组中的变量发生改变时,useEffect就会执行

先来看看多个state时,其中一个state更新,useEffect的反应(同一个组件中可以多次使用useState)

    // 另起一个用来存储年龄的state(允许多次使用useState)
    const [age, setAge] = useState(22);
    // 更新age
    const handleClick = ()=>
        setAge(age+1);
    

    // 当页面加载或重新渲染时,打印提示语
    useEffect(()=>
        console.log("useEffect正在执行中。。。",age)
    )

创建一个button按钮,点击一下,就修改age:

<button onClick=handleClick>点击一下年龄+1</button>

效果:

此处我修改了useEffect的输出函数,多加了年龄的打印,这样看得更清楚些。可以看到,无论是修改age还是添加书目,都会触发useEffect




然后,我们使用useEffect的第二个参数,限定useEffect的使用范围

    // 添加第二个参数,当book更新时,才触发打印
    useEffect(()=>
        console.log("useEffect正在执行中。。。",age)
    ,[ books ])

效果:一开始页面加载,useEffect会先执行一次;然后我点击增加age,点击两次,都是没有打印输出的(但age有在修改,点击两次,age值为24);最后我添加了书目,才有了打印。可见,限制useEffect的使用范围已生效




我们还可以在useEffect中将输入的书目进行本地存储

本地存储:localStorage

从文本框输入的书名,网页刷新后就不见了。如果我们存储起来,刷新的时候也能展示新输入的书目

  • 每次数据更新时都存到localStorage:
    // 本地存储  BookList.js
    useEffect(()=>
        // console.log("useEffect正在执行中。。。")
        localStorage.setItem("books", JSON.stringify(books));
    ,[ books ])
  • 刷新页面时从localStorage中取出之前的数据,如果第一次加载,就展示初始化的书目即可(也就是《我们仨》《我的阿勒泰》《蒋勋说<红楼梦>》三本书):
    // 刷新页面时从localStorage中取出之前的数据
    const [books, dispatch] = useReducer(BookReducer, initBooks, ()=>
        const result = localStorage.getItem('books');
        return result ? JSON.parse(result) : initBooks
    )

效果:

  1. 一开始加载页面,展示初始化的三本书;
  2. 然后我加了一本书名,页面展示4本书名;
  3. 最后我点击左上角的刷新,4本书名还在

useContext的使用

接着是useContext。
Context-API获取props数据,有两种方法:

  • 一种是通过contextType,只能获取离该组件最近的context,且函数组件不能使用;
  • 另一种是consumer,需要包裹住想要渲染的标签,可以获取多个context。

上一篇文章中,我们嵌套使用多个context时,代码是这样的:

代码稍微长了一点

如果用useContext,就会简洁很多

import React,  Component,useContext  from 'react'
import  ThemeContext  from '../contexts/ThemeContext';
import  GreetingContext  from '../contexts/GreetingContext';

const Navbar = ()=>
    const greetingContext = useContext(GreetingContext);  // GreetingContext使用
        const themeContext = useContext(ThemeContext);      // ThemeContext使用
        const  isAGirl, toggleGreeting  = greetingContext;
        const  isLightTheme, light, dark  = themeContext;
        const theme = isLightTheme ? light : dark;
        return (
            <nav style= background: theme.bg, color: theme.font >
                <h1>Context App</h1>
                <div onClick=toggleGreeting>
                     isAGirl ? 'hello,girl~' : 'hello,boy~'
                </div>
                <ul>
                    <li>Home</li>
                    <li>About</li>
                    <li>Contact</li>
                </ul>
            </nav>
        )

export default Navbar;

useReducer的使用

       我们知道,除了context,还有一种方法可以统一管理数据,那就是redux。redux提供了一个store来管理数据,而数据的更新,是交由reducer来执行的,ReactHooks也提供了这样的方法——useReducer,可以统一管理数据,增强代码的可维护性和可读性

       在useState的例子中,我们把数据的存储、数据的修改方法都写在了使用数据的组件里,这个组件既要管理数据,又要展示数据。我们可以使用useContext来抽离数据,用useReducer抽离数据的更新操作,不论哪个子组件,都能调用dispatch派发action行为,就像这样:

BookReducer.js文件中设置action

import React from 'react'
import v4 as uuidv4 from 'uuid'

const BookReducer = (state, action)=>

    switch (action.Type)
        case "ADD_BOOK":
            return [...state,title:action.book.title, id:uuidv4()]
        
    


export default BookReducer;

BookList.js文件中接收,并把dispatch传递给子组件AddBook去使用

import React,  useState, useEffect,useContext,useReducer  from 'react'
import AddBook from './AddBook'
import v4 as uuidv4 from 'uuid'
import  BookContext  from '../context/BookContext'

const BookList = () => 
    const books, dispatch = useContext(BookContext);
    
    // 当页面加载或重新渲染时,打印提示语
    useEffect(()=>
        console.log("useEffect正在执行中。。。")
    ,[ books ])


    return (
        <div className='book-list'>
            /* 展示数据:书目 */
            <ul>
                books.map(book => 
                    return (
                        <li className='title' key=book.id>book.title</li>
                    )
                )
            </ul>
            /* 将更新书目的方法传递给子组件,让子组件执行 */
            /* <AddBook addBook=addBook /> */
            <AddBook dispatch=dispatch />
        </div>
    )


export default BookList;

AddBook.js文件接收BookList传来的dispatch,将用户输入的书名填入action并派发

import React,  useState  from 'react'

// 添加新书目
// 接收addBook方法
const AddBook = (dispatch) => 
    // 初始化title为空,即用户还未输入想要增加的书目
    const [ title, setTitle ] = useState('');

    // 提交时,调用addBook方法,把新增的title返回
    const handleSubmit = (e)=>
        e.preventDefault();
        // addBook(title);
        dispatch(Type:"ADD_BOOK",book:title)
        setTitle("");
    
    return (
        // 用户输入书名并提交
        <form onSubmit=handleSubmit>
            <input type="text" placeholder='书名'
                onChange=(e) => setTitle(e.target.value) value=title />
            <input type='submit' placeholder='添加书目' />
        </form>
    )


export default AddBook;

效果依然还是:

  1. 展示初始化的书目;
  2. 在文本框中输入书名后点击添加,更新books,然后展示


关于“ReactHooks基本使用”就到这里啦~ 谢谢支持!

《你今天真好看》中两张图,如有不妥请联系我,谢谢

以上是关于React入门之ReactHooks基本使用的主要内容,如果未能解决你的问题,请参考以下文章

React入门之Redux:react-redux基本使用

React入门之Redux:react-redux基本使用

React Native 中带有 React Hooks 的基本全局状态

React入门之Redux:手动模拟Redux的基本流程

React入门之Redux:手动模拟Redux的基本流程

React Hooks用法大全