redux&react-redux初探

由Vue转React,耕耘下redux笔记
redux中文官方文档
react-redux API文档

建议写个todoList来熟悉新技术:可clone 刚写的todolist

在这里插入图片描述

一张图说清 React-Redux ,Redux , React 三者到底是什么关系。

  • Redux: 首先 Redux 是一个应用状态管理js库,它本身和 React 是没有关系的,换句话说,Redux 可以应用于其他框架构建的前端应用,甚至也可以应用于 Vue 中。
  • React-Redux:React-Redux 是连接 React 应用和 Redux 状态管理的桥梁。React-redux 主要专注两件事,一是如何向 React 应用中注入 redux 中的 Store ,二是如何根据 Store 的改变,把消息派发给应用中需要状态的每一个组件。
  • React :就不说了
    在这里插入图片描述

redux篇

以todolist为例,redux在使用中大致表现为UI组件、action、constants、reduces四大部分:
在这里插入图片描述
下面开始分别介绍,大致流程为:首先在constants设置type参数,接着action声明要修改的对象类型(补上type参数),然后在 reduce(接收旧的 state 和 action两个参数,返回新的state)写修改数据的逻辑,最后在UI组件触发逻辑。

Contents:设置Action需要的type参数字段,Reduce会依据这字段做不同逻辑

export const TODO_DEL = "TODO_DEL";

Action:只描述state的变化而不更新

在 Redux中,action本质是一个JavaScript 普通对象,可以理解为store数据的载体。
官网说:唯一改变 state 的方法就是触发 action,那是因为在UI组件中,dispatch(todoDel (!nowDone)); dispatch了action暴露出来的todoDel ,然后这个todoDel 执行了reduce逻辑,然后发生了state改变。

export const todoDel = (id) => ({
  type: TODO_DEL,
  id,
});

在UI组件里,只需把 action 创建的结果传给 dispatch() 方法,即可发起一次修改或更新数据(前提是reduce里写了逻辑)。

dispatch(todoDel (text))
//或者创建一个被绑定的 action 创建函数 来自动 dispatch:
const boundAddTodo = text => dispatch(addTodo(text))
//然后直接调用它们:
boundAddTodo(text);

store 里能直接通过 store.dispatch() 调用 dispatch() 方法,但多数情况下会使用 react-redux 提供的 connect() 来调用。bindActionCreators() 可以自动把多个 action 创建函数绑定到 dispatch() 方法上。


Reducer:根据Action变化更新State

Reducers :就是纯函数,它接收旧的 state 和 action两个参数,返回新的 state的函数。且依据应用状态的变化响应 actions 并将数据更新。

注意每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。

//TODO_DEL:依据type参数,处理不同的action逻辑
export default function todo(state = 旧state数据, action) {
  switch (action.type) {
    case TODO_DEL:
      return state.filter((item) => item.id !== action.id);
    case TODO_CHEK_ALL:
      return state.map((item) => ({ ...item, done: action.done }));
      ...
    default:
      return state;
  }
}

永远不要在 reducer 里做这些操作:

  • 修改传入参数;
  • 执行有副作用的操作,如 API 请求和路由跳转;
  • 调用非纯函数,如 Date.now()Math.random()
  • 使用 combineReducers() 将多个 reducer 合并成为一个

谨记 reducer 一定要保持纯净。只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。

UI组件

上面一套流程走完后,就可以在UI组件触发事件,更新数据了。

import { useDispatch } from "react-redux";
  const dispatch = useDispatch();
  const handleChangeAll = () => {
    dispatch(todoCheck(!nowDone));
  };

Store:将它们联系到一起的对象

创建一个 Redux store 来以存放应用中所有的 state:

createStore(reducer, [preloadedState], enhancer)

  • reducer:接收旧的 state 和 action,返回新的 state树

Store 有以下职责:

发起 Actions

// 打印初始状态
console.log(store.getState())

// 注意 subscribe() 返回一个函数用来注销监听器
const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

// 发起一系列 action
store.dispatch(reducer的方法('Learn about actions'))

// 停止监听 state 更新
unsubscribe();

数据流

Redux 应用中数据的生命周期遵循下面 4 个步骤:

  1. 调用Action,可以在任何地方 store.dispatch(action)
//Action 就是一个描述“发生了什么”的普通对象 
{ type: 'LIKE_ARTICLE', articleId: 42 }
  1. store将(当前的 state 树和 action) 传入 reducer 函数():
// 当前应用的 state
 let previousState = {
   A: [],
   B: "hello"
 } 
 
  // 将要执行的 action
 let action = {
   type: 'ADD_TODO',
   text: 'Understand the flow.'
 }
 
let nextState = todoApp(previousState, action)
  1. 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树

Redux 原生提供combineReducers()辅助函数,来把根 reducer 拆分成多个函数,用于分别处理 state 树的一个分支。

//假如有两个 reducer 
 function A(state = [], action) {
   return nextState
 }

 function B(state = 'Redux', action) {
   return nextState
 }

 let todoApp = combineReducers({
   A,
   B
 })

当你触发 action 后,combineReducers 返回的 todoApp 会负责调用两个 reducer:

 let nextA = A(state.A, action)
 let nextB = B(state.B, action)

然后会把两个结果集合并成一个 state 树:

return {
   A: nextA,
   B: nextB
 }
  1. Redux store 保存了根 reducer 返回的完整 state 树

这个新的树就是应用的下一个 state!所有订阅 store.subscribe(listener) 的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state。

React Redux 应该调用 component.setState(newState) 来更新。

一些Api

useSelector

selector 回调函数会把storeState返回给你 你再进行筛选返回自己想要使用的数据

const num = useSelector(state => state.num);
createStore

通过createStore将state存入store

const store = createStore(reducer, initialState);

再通过Provider向子组件暴露store,通过store在父子组件之间共享状态

 <Provider store={store}>
     <Son />
 </Provider>
useDispatch

通过useDispatch 可以获取dispatch,用来提交更新

import { useDispatch } from "react-redux";
const dispatch = useDispatch();
dispatch(todoDel(id));
context :createContext -> useContext

一种组件传值方式,能轻松拿到组件值。官方Hooks的API

//null可以为父组件要传递的值,不一定是null
const newContext = createContext(null);

const [age,setAge] = setAge(0)
//通过value传递值
<newContext.Provider value={{age,setAge}}>
   <Father>
       <Son /> 
   </Father>
</newContext.Provider >
        
//son组件
  const {age,setAge} = useContext(newContext)
  const add=()=>{
    setAge(age=>age+1)
  };
useEffect(callback,[])

React会在每次渲染完后调用useEffect,包括第一次加载渲染DOM

接受两个参数,一个处理函数,另一个关联的状态或数组,这个变了就重新执行

useCallback + useMemo

他两个使用和 useEffect 差不多

解决的痛点:在函数组件中,定义在组件内的函数会随着状态更新而重新渲染,这样会影响的子组件频繁定义、渲染。

//父组件
function Father(){
   const [age,setAge]=useState(0)
   const handleClick = () => {
       setAge(age + 1)
   }
   return <Son />
}

采用useCallback +Memo后:

//使用Memo后确实不会影响了,但父组件传值过来呢
const Son = React.memo(function Son(){
    ...
})

//父组件:这样就不会
const childClick = useCallback(() => {}.[])
<Son click={childClick} />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值