React是一个用于构建用户界面的JavaScript库,解决了视图的UI层。但是对于状态管理目前还没有很好的解决方案。状态大致分为:反映UI变化的状态、本地创建的状态、服务端返回的数据状态等。面对社区里纷繁复杂的状态管理库,作为初学者不知如何选择比较好。本系列文章《React状态管理》也希望能帮助大家了解不同的状态管理方案(React官方自己提供以及社区中的一些库)可以做什么以及它们的优势。本文从React自身提供的组件状态管理入手。React的组件状态分为类组件时代的hooksAPI管理数据状态和当前函数组件。类组件State类组件以一种状态管理组件中的所有状态:获取状态数据、更新状态数据。从'react'导入React;classStateextendsReact.Component{constructor(){super();this.state={count:0,}}render(){return
count:{this.state.count}
this.setState({count:this.state.count+1})}>classcomponentcount}}exportdefaultState;函数式组件useStateReact16.8发布后,函数式组件成为了流行的选择。组件状态使用useState()函数,比类组件状态更详细,状态变量的每次更新都是替换而不是合并。如果更新依赖于之前的状态,你可以传递一个函数给setState并返回一个更新的值setState(preState=>newState)。熟悉Redux的朋友可能看着眼熟。这个函数更像是一个reducer函数吗?示例:useState实现计数器递增、递减和重置。从“反应”导入{useState};constState=()=>{const[count,setCount]=useState(0);return
countercount:{count}
setCount(count+1)}>增加setCount(preCount=>preCount-1)}>decreasesetCount(0)}>reset}导出默认状态;功能组件useReducer初见useReducer时,联想和Redux有什么关系?需要注意的是,它和Redux完全不一样,useReducer是ReactHooks提供的一个API,熟悉Redux的人可能看起来更熟悉。useReducer是useState的替代品,主要用于处理一些逻辑复杂的状态或者下一个状态依赖于上一个状态等。示例:使用useReducer重写上面的counter例子,可以和上面的useState做对比.从“反应”导入{useReducer}constCOUNT_INCREMENT='COUNT_INCREMENT';constCOUNT_DECREMENT='COUNT_DECREMENT';constCOUNT_RESET='COUNT_RESET';constinitialState={count:0,};constreducer=(state,action)=>{switch(action.type){caseCOUNT_INCREMENT:return{count:state.count+1};caseCOUNT_DECREMENT:return{count:state.count-1};caseCOUNT_RESET:return{计数:initialState.count};默认值:返回状态;}};constState=()=>{const[state,dispatch]=useReducer(reducer,initialState);return
计数器count:{state.count}
dispatch({type:COUNT_INCREMENT})}>增加dispatch({type:COUNT_DECREMENT})}>减少dispatch({type:COUNT_RESET})}>重置}exportdefaultState;useReducer实现Todos使用useReducer实现了一个稍微复杂的功能,比如Todos,它有创建、更新、移除待办事项的功能。你可以想象如果换成useState会怎样处理?会不会更麻烦?reducer在目录中实现了reducer所需要的逻辑。定义的initialState变量和reducer函数都是为useReducerHook准备的。这里的reducer函数是一个纯函数//src/reducers/todos-reducer.jsxexportconstTODO_LIST_ADD='TODO_LIST_ADD';exportconstTODO_LIST_EDIT='TODO_LIST_EDIT';exportconstTODO_LIST_REMOVE='TODO_LIST_REMOVE';constrandomID=()=>Math.floor(Math.random()*10000);exportconstinitialState={todos:[{id:randomID(),content:'todolist'}],};constreducer=(state,action)=>{switch(action.type){案例TODO_LIST_ADD:{constnewTodo={id:randomID(),content:action.payload.content};返回{todos:[...state.todos,newTodo],}}caseTODO_LIST_EDIT:{return{todos:state.todos.map(item=>{constnewTodo={...item};if(item.id===action.payload.id){newTodo.content=action.payload.content;}returnnewTodo;})}}caseTODO_LIST_REMOVE:{返回{todos:state.todos.filter(item=>item.id!==action.payload.id),}}默认值:返回状态;}}导出默认减速器;创建Todos组件,开发下面的待办事项组件,细分为三个组件:TodoAdd、Todo、Todos。在Todos组件中使用useReducer获取组件所需的状态(state)和更新状态的方法(dispatch)分别在TodoAdd和Todo组件中添加、更新、删除待办事项。下面我们使用React推荐的组合组件模式,可以将父组件的数据传递给Subassembly。import{useReducer,useState}from"react";importreducer,{initialState,TODO_LIST_ADD,TODO_LIST_EDIT,TODO_LIST_REMOVE}from"../../reducers/todos-reducer";constTodoAdd=({dispatch})=>{const[内容,setContent]=useState('');返回<>
setContent(e.target.value)}/>{dispatch({type:TODO_LIST_ADD,payload:{content}})}}>添加>};constTodo=({todo,dispatch})=>{const[isEdit,setIsEdit]=useState(false);const[content,setContent]=useState(todo.content);返回{!isEdit?<>{todo.content}setIsEdit(true)}>编辑dispatch({type:TODO_LIST_REMOVE,payload:{id:todo.id}})}>删除>:<><输入值={content}type="text"onChange={e=>setContent(e.target.value)}/>{setIsEdit(false);dispatch({type:TODO_LIST_EDIT,payload:{id:todo.id,content}})}}>更新setIsEdit(false)}>取消>}
}constTodos=()=>{const[state,dispatch]=useReducer(reducer,initialState);返回<>{state.todos.map(todo=>)}>}export默认待办事项;综上所述,useState适合定义一些单一的状态,useReducer适合逻辑比较复杂的状态。一个好的经验法则是:“如果状态是基本数据类型(字符串、数字、布尔值)。你可以选择useState。如果是数组或对象或其他复杂类型或复杂逻辑,最好选择useReducer”。但两者都是组件状态管理,当多个组件协同工作时,不得不面对组件间“数据通信”的问题。React组件数据状态流是一个“单一数据流”的概念。简单的组件可以通过props传递数据状态。当组件过多时,逐层传递道具的方式有点过于繁琐,难以维护。