useReducer

简介

1 .类似于redux中的功能,但是这个传值怎么操作

import React,{useState,useEffect,useReducer}from 'react'


// 怎么传值进去呢,全都挂载到action里面
function reducer(state,action){
    switch (action.type){
        case 'add':
            return {count:state.count+action.value};
        case 'sub':
            return {count:state.count-action.value};
        default:
            throw new Error()
    }
}

function App(){
    const [state,dispatch]=useReducer(reducer,{count:0})

    return (
        <>
            点击次数 {state.count}

            <button onClick={()=>dispatch({type:"add",value:10})}>+</button>
            <button onClick={()=>{dispatch({type:"sub",value:1})}}>-</button>
        </>  
    )
}

export default App

useReducer基础

1 .任何使用useState的地方,都可以替换成useReducer
2 .单例替代useState的例子

const initState=0
// const reducer=(state,action)=>{
//     switch (action){
//         case 'add':return state+1
//         case 'sub':return state-1
//         case 'reset':return 0
//         default:throw new Error("Unexcepted action")
//     }
// }
// 针对单个值,而且对每一个情况都进行了分类


// 传入第二个参数
const reducer=(state,action)=>{
    switch(action.type){
        case 'add':return state+action.value
        case 'sub':return state-action.value
        case 'reset':return 0
        default:throw new Error("Unexcepted action")
    }
}

<button onClick={()=>dispatch('add')}>+1</button>
            <button onClick={()=>dispatch('sub')}>-1</button>
            <button onClick={()=>dispatch('reset')}>0</button>

            <button onClick={()=>dispatch({type:"add",value:10})}>+10</button>
            <button onClick={()=>dispatch({type:"sub",value:1})}>-1</button>
            <button onClick={()=>dispatch({type:"reset",value:0})}>reset</button>

3 .state是一个对象

const initState={
    count1:0,
    count2:1
}
const reducer=(state,action)=>{
    switch(action.type){
        case "add1":
            return {...state,count1:state.count1+action.value}
            // 对象的解构,先放入原来的对象,拿后面新的处理后的key覆盖前面已经放入的数据.相同的key的值,会使用后面的value
        case "add2":
            return {...state,count2:state.count2+action.value}
        default:
            return state
    }
}
const [state,dispatch]=useReducer(reducer,initState)
    const [state2,dispatch2]=useReducer(reducer,initState)
    // 多次使用,可以使用同一份数据复制多多个模板,且互相之间不会影响

    return (
        <>
            count1:{state.count1}
            <button onClick={()=>dispatch({type:"add1",value:10})}>+10</button>
            count2:{state.count2}
            <button onClick={()=>dispatch({type:"add2",value:1})}>+1</button>
            count2-1:{state2.count1}
            <button onClick={()=>dispatch2({type:"add1",value:1})}>+1</button>
            count2-2:{state2.count2}
            <button onClick={()=>dispatch2({type:"add2",value:10})}>+10</button>
            
        </>
    )

其他笔记

1 .hooks每次render都有自己的props和state,可以认为每次render的内容都会形成一个快照保存下来,函数被销毁了,但是变量会被react报留下来
2 .当状态变更发生render的时候,就形成了n个render状态,而每个render状态读拥有自己固定不变的props和state。
3 .

useState和useReducer的区别

1 .react 内部,useState就是用useReducer实现的,useState返回的函数内部封装了一个dispatch

使用场景区别,为什么要使用reducer

1 .更容易管理大量状态-一个完整流程涉及到的一些相关变量适合用这个写,注意一定是要有关联的

function LoginPage() {
        const [name, setName] = useState(''); // 用户名
        const [pwd, setPwd] = useState(''); // 密码
        const [isLoading, setIsLoading] = useState(false); // 是否展示loading,发送请求中
        const [error, setError] = useState(''); // 错误信息
        const [isLoggedIn, setIsLoggedIn] = useState(false); // 是否登录

        const login = (event) => {
            event.preventDefault();
            setError('');
            setIsLoading(true);
            login({ name, pwd })
                .then(() => {
                    setIsLoggedIn(true);
                    setIsLoading(false);
                })
                .catch((error) => {
                    // 登录失败: 显示错误信息、清空输入框用户名、密码、清除loading标识
                    setError(error.message);
                    setName('');
                    setPwd('');
                    setIsLoading(false);
                });
        }
        return ( 
            //  返回页面JSX Element
        )
    }
//useState实现登陆界面.

2 .更容易被其他开发者理解:这一条不算吧.可以被替代,如果用immtable-helper,修改起来数据也是非常容易被理解的
3 .更容易被测试.这个好像无法被替代.
4 .使用reducer的场景

1 .你的state是一个数组或者对象
2 .你的state变化很复杂,经常一个操作关联到很多state
3 .你希望构建自动化测试用例来保证程序的稳定性
4 .你需要在深层子组件里面去修改一些状态

5 .代码

import React,{useState,useCallback,useMemo,useContext,useReducer} from 'react'

// count的reducer:把一个数据的变化给你搞的清清楚楚
function reducer1(state,action){
    // 接收当前的state,触发动作,返回最新的state
    switch(action.type){
        case 'add':
            return {count:state.count+action.value};
        case 'sub':
            return {count:state.count-action.value}
        default:
            throw new Error()
    }
}
// 这样看起来,一个数据就要写一个,有点类似于前后端的协议操作,相当之规范.immutable那种操作也是写在这里的.我觉得既然已经开始拆分了,那就贯彻到底.这样不是非常的清爽,如果一个里面有很多,那不就是根据dispatch的名字看不出来了么.

// name的reducer
function reducer2(state,action){
    switch(action.type){
        case 'change':
            console.log(action)
            // 没有数据变化的时候也会执行该操作,其实这里已经明确了你发出dispatch的时候已经肯定要发生改变了
            return {name:action.value};
        default:
            throw new Error()
    }
}
// reducre是一个纯函数,没有任何副作用,ui,相同的输入一定返回相同的输出,非常容易做单元测试

// 还有一个就是感觉是非常透明的,useState感觉还是隔着一层东西

// 操作注意竖向,处理的state必须是immutable,这意味着永远都不要直接修改参数中的state对象,reducer函数返回的每次都是一个新的state object


// 但是如果仅仅是为了便于测试和理解的化,


// 复杂流程的相关数据管理
const initState={
    name:'刘华强',
    pwd:'123456',
    isLoading:false,
    error:'',
    isLoggedIn:false,
}

function loginReducer(state,action){
    switch(action.type){
        case "login":
            return {
                ...state,
                isLoading:true,
                error:''
            }
        case "success":
            return{
                ...state,
                isLoading:false,
                isLoggedIn:true,
            }
        case 'error':
            return {
                ...state,
                error:action.payload.error,
                name:'',
                pwd:'',
                isLoading:false
            }
        default:
            return state
    }
}

export default function(){
    const [stateCount,dispatchCount]=useReducer(reducer1,{count:0})
    // 传入:操作,默认值
    // 返回:当前的值,触发动作的函数
    const [stateName,dispatchName]=useReducer(reducer2,{name:'刘华强'})

    const [stateLogin,dispatch]=useReducer(loginReducer,initState)
    const {name,pwd,isLoading,error,isLoggedIn}=stateLogin
    // 这样取值不会每次都重新渲染吧..................啊啊啊啊啊啊啊啊啊啊啊啊

    function login(){
        dispatch({type:'login'})
        if(Math.random>0.5){
            // 模拟成功
            setTimeout(()=>{
                dispatch({type:'success'})
            })
            // 改变状态的时候确实爽多了,而且跟这一个操作相关的变量我们都一起修改了.避免漏改,或者改错.所以一个操作需要关联到更多的变量的时候,可以用这种方式来组织代码.

            // 分开了how和what,让我们的代码可以像用户的行为一样,更加清晰

            // 感觉就像搭积木一样,这样写代码让我知道我下一次可以写的更好
        }else{
            // 模拟失败
            dispatch({type:"error",payload:{error:"超时了"}})
        }
    }

    return(
        <div>
            <button onClick={()=>dispatchCount({type:"add",value:1})}>{stateCount.count}</button>
            
            <button onClick={()=>dispatchName({type:"change",value:"菲菲"})}>{stateName.name}</button>

            测试useReducer
            <hr />
            <h3 onClick={login}>啦啦啦</h3>

            名字{name}
            密码{pwd}
            当前状态{isLoading===true?"正在登陆中":"登陆完成"}
            登陆{error===true?"失败":'成功'}
            是否登陆{isLoggedIn==true?"已经登陆":"没有登陆"}


        </div>
    )
}

跨组件修改信息结合context

1 .

SVN diff

1 .http://www.ruanyifeng.com/blog/2012/08/how_to_read_diff.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容