Redux 基础应用.

安装包

yarn add redux

来自 阮一峰

  • 为了让代码各部分职责清晰、明确,Redux 提出三个核心概念,需要我们写代码的时候遵守。

    a,action(动作):描述要做的事情(要干啥)。

    b,reducer(函数):更新状态(怎么干)。

    c,store(仓库):整合 action 和 reducer(谁来指挥)。

  • 通过例子来理解三个核心概念。

    a,action:相当于公司里面要做的事情,比如打扫卫生这个事等。

    b,reducer:相当于公司的员工,负责执行。

    c,store:相当于公司的老板。

    d,流程:老板(store)分配(dispatch)要做的事情(action)给员工(reducer),员工干完活把结果交给老板。

    e,在视图当中,通过 store dispatch 一个 action,reducer 会自动收到通知来更新 state,state 一旦变化,说有使用 state 的视图自然就变了。

Actions

用于定义方法

export const decrement =(payload)=>{
     type:'DECREMENT',
     payload
}

export const increment=(payload)=>{
     type:'INCREMENT',
     payload
}

Reducers

用于根据 Actions 里的方法来修改, 本质上是一个函数

//  用于处理action状态
//  参数:默认状态.action=>(type payload)
export default function counter (state = 10, action) {
  // 根据action.type 的不同做不同的处理
  switch (action.type) {
    case 'DECREMENT':
      return state - action.payload
    case 'INCREMENT'
      return state + action.payload
    // 默认一般需要返回一个 state
    default:
      return state
  }
}

-------------------------------------------

export default function counter (state = 10, action) {
   if(action.type === 'DECREMENT'){
       return state - action.payload
  }
   if(action.type === 'INCREMENT'){
       return state + action.payload
  }
       return state
}

Reducers 是一个纯函数.

纯函数定义

  1. 相同输入就能得到相同的输出

    a. 不得改写参数,不能使用全局变量

    b. 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果

    c. 不包含副作用处理.,副作用:AJAX请求.操作本地数据.或者操作函数外部变量

  2. 好处:代码简洁.方便测试.方便性能优化.

 Store

import { createStore } from 'redux'
import counterReducer from './reducers'
import { increment, decrement } from './actions'
// 参数:传递一个 reducer
// 返回值:store 实例
const store = createStore(counterReducer)

// 先订阅后续才能被监听到.一定要写在事件触发之前
// unsubscribe 用于停止监测
store.subscribe(() => {
  // 一旦状态变化了.就会触发这里.
  console.log(store.getState());
})

// 当前属性加5
store.dispatch(increment(5))
//当前属性减5
store.dispatch(decrement(3))


export default store

执行流程:

获取默认值的执行过程
1. 只要创建 store,Redux 内部就会调用一次 reducer,打印试一下 console.log(action.type)。

2. 类似:reducer(undefined, {type: "@@redux/INITv.a.4.t.t.p"})。

3. 这一次调用 reducer 的目的:获取状态的默认值。

4. 因为传入的状态值是 undefined ,并且是一个随机的 action type,所以!

5. a,状态值因为 undefined,所以,我们设置的默认值就会生效,比如,此处的:10。

6. b,因为是一个随机的 action type,所以,reducer 中 switch 一定无法命中,那就一定会走 default,也就是直接返回了状态的默认值,也就是:10。

7. Redux 内部拿到这个数据(比如此处的 10)以后,就用这个数据作为了 store 中的最新状态值。

8. 因此,将来当我们调用 store.getState() 方法来获取 Redux 状态值的时候,拿到的就是 10 了。

React-Redux

为了将React Redux 两个结合在一起.使用

1. 导入包 import { Provider } from 'react-redux'

2. 包裹对应组件 并传递store  ReactDOM.render(

   <Provider store={store}>

   <App />

   </Provider>,

   document.querySelector('#root'))

3. 导入useSelector, useDispatch

4. 导入increment, decrement

5. 生成const state = useSelector(state=>state)

6. const dispatch = useDispatch()

7. 使用则是state

8. dispatch.increment(你需要的参数) 

9. dispatch.decrement(你需要的参数) 

10. state数据是公共的.哪里修改都会更改全部视图效果

Reducer 的分离与合并


 1. 把 reducers 中的直接导出改为按需导出
 2. 使用combineReducers接收.默认值为 counter user.
 3. 定义user. 如果不是user 要修改.
 4. 在需求的地方再导出使用.


---------------------------------------------------------

import { createStore, combineReducers } from 'redux'
import { counter, user } from './reducers'

const username = combineReducers({
  counter,
  user,
})
const store = createStore(username)
export default store
1. 如果使用大型项目则可以使用
单独封装一个js文件定义
export const TODO_DEL = 'TODO_DEL'
export const TODO_CHANG_STATUS = 'TODO_CHANG_STATUS'
export const TODO_ADD = 'TODO_ADD'
export const TODO_CHECKED = 'TODO_CHECKED'

---------------------------------------------

2. 在actions中定义
import { TODO_CHECKED, TODO_DEL, TODO_ADD, TODO_CHANG_STATUS   } from "../constans"

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

export const changStatus = (id) => ({
  type: TODO_CHANG_STATUS,
  id
})

export const todoAdd = (name) => ({
  type: TODO_ADD,
  name,
  id: Date.now(),
  done: false
})

export const todochecked = (done) => ({
  type: TODO_CHECKED,
  done
})

------------------------------------------

3. 在reducers中定义
import { TODO_CHECKED, TODO_DEL, TODO_CHANG_STATUS, TODO_ADD } from "../../constans"
const initState = [
  {
    id: 1,
    name: '吃饭',
    done: true,
  },
  {
    id: 2,
    name: '睡觉',
    done: false,
  },
]

export default function todo (state = initState, action) {
  switch (action.type) {
    case TODO_DEL:
      if (action.type === TODO_DEL) {
        return state.filter((item) => item.id !== action.id)
      }
    case TODO_CHANG_STATUS:
      return state.map((item) => {
        if (item.id === action.id) {
          return {
            ...item,
            done: !item.done
          }
        }
        else {
          return item
        }
      })
    case TODO_ADD:
      const { type, ...res } = action
      return [
        res,
        ...state
      ]
    case TODO_CHECKED:
      return state.map((item) => {
        return {
          ...item,
          done: action.done
        }
      })
    default: state
  }
  return state
}


------------------------------------------------------

4.最后在需求的组件模块中使用方法
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { todoAdd } from '../actions'
export default function Header () {
  const [name, setName] = useState('')
  const dispatch = useDispatch()
  const handlekey = (e) => {
    if (e.keyCode === 13) {
      if (name.trim().length === 0) return alert('格式有误')
      dispatch(todoAdd(name))
      setName('')
      e.target.value = ''
    }
  }
  return (
    <>
      <header className='header'>
        <h1>todos</h1>
        <input
          className='new-todo'
          placeholder='What needs to be done?'
          autoFocus
          onChange={(e) => setName(e.target.value)}
          onKeyDown={handlekey}
        />
      </header>
    </>
  )
}

定义顺序.

1. index.js 导入

import store from './store'
import { Provider } from 'react-redux'

ReactDOM.render(
<Provider store={store}>
  <App/>
</Provider >,
document.querySelector('#root'))

2. store/index.js 导入中间件和 reducer

import { createStore, applyMiddleware } from 'redux'
// 用于发起异步请求的包
import thunk from 'redux-thunk'

import reducer from './reducers'

export default createStore(reducer, applyMiddleware(thunk))

3. reducers/index.js 根据模块导入导出 在reducers中定义所对应的模块方法

// 用于合并导出
import { combineReducers } from 'redux'
import channel from './channel'
import news from './news'
export default combineReducers({
  channel,
  news,
})

4. constants(用于定义常量,可有可无,根据需求.) => actions => reducers 按这个顺序一次定义模块中需要修改的数据方法

最后在模块中使用

import { useDispatch, useSelector } from 'react-redux'

const list = useSelector((state)=> state )

const dispatch = useDispatch()

关于异步请求方法:

1.下包

yarn add redux-thunk

2.导入

import thunk from 'redux-thunk'

3.导出使用

export default createStore(reducer, applyMiddleware(thunk))

4.具体定义方式

import axios from 'axios'

export const getChannelListAc = (payload) => ({
  type: CHANNEL_GET,
  payload,
})

export const getChannelList = () => {
  return async (dispatch) => {
    const res = await axios.get('http://xxxx')
    dispatch(getChannelListAc(res.data))
  }
}

5.使用.获得得到数据

 const dispatch = useDispatch()
  useEffect(() => {
    dispatch(getChannelList())
  }, [dispatch])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值