react-hooks学习

react hooks在react16.8版本以后,推出的一组函数式的api.专门用于函数组件,使函数组件也能像类组件一样使用state和生命周期等一些特性。

1.useState

useState可以使函数组件处理数据的状态。它只能放在函数组件中,不可以用在判断和循环语句中。

let [state,setState] = useState(initialState);

 useState接收一个state初始值,返回这个state和设置state的函数;设置state的函数不能自动合并state中的数据,需要手动合并。 

代码示例:

1.未封装版form表单收集数据

import { useState } from 'react';


// 使用函数实现表单数据收集
// 不需要访问this
// 代码更简洁
function Form() {

  let [ email, setEmail ] = useState('');
  let [ password, setPassword ] = useState('');

  return (
    <div>
        <h1>react hooks</h1>
        <div>
            <input type="text" name="email" placeholder="输入邮箱" value={email} onChange={e => setEmail(e.target.value)} />
        </div>
        <div>
            <input type="password" name="password" placeholder="输入密码" value={password} onChange={e => setPassword(e.target.value)} />
        </div>
        <div>
           <button onClick={e => console.log('Form 数据:',email,password)}>提交</button>
        </div>
    </div>
  );
}

export default Form;

2.自定义hook封装版form表单收集数据 

//hooks/useForm.js
import { useState } from 'react';

// 收集表单数据的自定义hooks
export default function useForm(initialVal){
    let [ values, setValues ] = useState(initialVal);

    // 返回一个数组
    return [
        values,
        // 箭头函数方法
        e => {
             //useState不能自动合并state的数据,以下通过解构,新值覆盖的方式来合并
            // 解构原先的对象,从e.target中收取最新的一个[name:value],覆盖原先的[name:value],此操作将数据进行合并
            setValues({
                ...values,
                [e.target.name]: e.target.value
            })
        }
    ]
}
/src/FormComp.js
import useForm from './hooks/useForm';


// 使用函数实现表单数据收集
// 不需要访问this
// 代码更简洁
function FormComp() {

  let [ values, handleChange ] = useForm({ email: '', password: '' });

  return (
    <div>
        <h1>react hooks</h1>
        <div>
            <input type="text" name="email" placeholder="输入邮箱" value={values.email} onChange={handleChange} />
        </div>
        <div>
            <input type="password" name="password" placeholder="输入密码" value={values.password} onChange={handleChange} />
        </div>
        <div>
           <button onClick={e => console.log('Form 数据:',values.email,values.password)}>提交</button>
        </div>
    </div>
  );
}

export default FormComp;

2.useEffect

 useEffect的四个用法

  • 注册一个生命周期didMount和didUpdate
  • 增加清除操作(返回一个清除函数,在该函数中清除);比如清除定时器,绑定的事件等等,类似于在willUnmount生命周期中执行一些解除的操作
  • 只注册一次didMount和willUnmount(给useEffect的第二个参数传入空数组);常用于初次发送异步请求此类操作
  • 性能优化,在某个条件下更新

代码示例:

//用法一 注册一个生命周期didMount和didUpdate

import { useEffect,useState } from 'react';

export default function LearnEffect(){

    let [ count,setCount ] = useState(0);

    //此函数会在didMount和didUpdate时执行
    useEffect(() => {
       console.log('render: '+ count);
       console.log('didMount&&didUpdate');
    });

    return (
        <div>
            <h1>useEffect 用法</h1>
            <p>{count}<p>
            <button onClick={() => setCount(count + 1)}>+1</button>
        </div>
    )
}
//用法二 增加清除操作(返回一个清除函数,在该函数中清除);比如清除定时器,绑定的事件等等,类似于在willUnmount生命周期中执行一些解除的操作

useEffect(() => {
   const subscription = props.source.subscribe();
   //返回清除函数
   return function cleanup(){
       //清除订阅
       subscription.unsubscribe();
   }
})
//用法三 只注册一次didMount和willUnmount(给useEffect的第二个参数传入空数组);常用于初次发送异步请求此类操作
//形成闭包,无法获取最新的state,setState 需要传递函数

//当传入空数组时,效果相当于拥有了didMount和willUnmount两个生命周期
useEffect(() => {
   const subscription = props.source.subscribe();
   //返回清除函数
   return function cleanup(){
       //清除订阅
       subscription.unsubscribe();
   }
},[])
//用法四  性能优化,在某个条件下更新

useEffect(() => {
   const subscription = props.source.subscribe();
   //返回清除函数
   return function cleanup(){
       //清除订阅
       subscription.unsubscribe();
   }
//传入非空数组,则在此条件下进行渲染更新
},[props.id])

3.useRef

代替类组件中的React.createRef() ,在函数组件中使用的ref.

import { useRef } from 'react';

export default function UseRefTest(){
    
    // 声明一个元素,一开始不知道指向哪个标签,先标识为null
    const element = useRef(null);

    function handleClick(){
        console.log('获取input的值:', element.current.value);
    }

    return (
        <div>
            <input type="text" ref={element} />
            <button onClick={handleClick} >获取input的值</button>
        </div>
    )
}

 

4.useContext

通过createContext来创建上下文空间,Provider组件来传递值;通过以下两种方式来获取值:

  • Consumer组件中解构获取
  • useContext(上下文) 获取
import React, { useState, useContext, createContext } from 'react';

// 创建上下文空间
const NumContext = createContext();
console.log('NumContext:', NumContext);

function Son(){
    // const { num } = useContext(NumContext);
    // return <div>啦啦啦{num}</div>
    return (
        // useContext 消费者
        <NumContext.Consumer>
            {/* 内部可以接收到context的数据,通过解构使用 */}
            {
                ({num}) => <div>呵呵呵{num}</div>
            }
        </NumContext.Consumer>
    )
}

function Btn(){
    return (
        <NumContext.Consumer>
            {
                ({num,setNum}) => <button onClick={ () => { setNum(num + 1) }} >累加</button>
            }
        </NumContext.Consumer>
    )
}

export default function UseContextTest(){
    const [num,setNum] = useState(0);

    return (
        <div>
            {/* 
              *上下文空间提供器 
              单参传递,value={变量}
              多参处传递,value={ obj }  传递对象
            */}
            <NumContext.Provider value={{ num,setNum }}>
                <Son />
                <Btn />
            </NumContext.Provider>
        </div>
    )
}

 tips:跨文件时如何传递?

5.useReducer 

在函数组件中使用的reducer 

import React, { useReducer } from 'react';

// 定义一个关于num的reducer
function NumReducer(state, action){
    let newState = JSON.parse(JSON.stringify(state));
    switch (action.type) {
        case 'addNum':
            newState.num += action.value;
            break;
        default:
            break;
    }

    return newState;
}

export default function UseReducerTest(){
    // useReducer:传入手写reducer方法和原始state返回新state和dispatch进行使用
    const [state, dispatch] = useReducer(NumReducer, { num: 0});

    return (
        <div>
            <div>嘻嘻嘻{state.num}</div>
            <button onClick={ () => dispatch({ type: 'addNum', value: 1 }) } >累加</button>
        </div>
    )
}

延伸:

使用useReducer和useContext来实现简易react-redux

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

// 1-创建上下文空间
const NumContext = createContext();


function NumReducer(state, action){
    let newState = JSON.parse(JSON.stringify(state));
    switch (action.type) {
        case 'addNum':
            newState.num += action.value;
            break;
        default:
            break;
    }

    return newState;
}


function Son(){
    return (
        // 使用消费者
        <NumContext.Consumer>
            {
                ({state}) => <div>嘿嘿嘿{state.num}</div>
            }
        </NumContext.Consumer>
    )
}

function Btn(){
    return (
        // 使用消费者
        <NumContext.Consumer>
            {
                ({dispatch}) => <button onClick={ () => dispatch({ type: 'addNum', value: 1 }) } >累加</button>
            }
        </NumContext.Consumer>
    )
}


// useContext搭配useReducer实现react-redux
export default function UseReducerTest(){
    // useReducer:传入手写reducer方法和原始state返回新state和dispatch进行使用
    const [state, dispatch] = useReducer(NumReducer, { num: 0});

    return (
        <div>
            {/* 2-上下文空间传参,传参对象为useReducer的返参 */}
            {/* 使用提供者 */}
            <NumContext.Provider value={{state, dispatch}}>
                <Son />
                <Btn />
            </NumContext.Provider>
        </div>
    )
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值