react-redux项目结构

项目结构

  • public

  • src

    • store redux仓库目录

      • actionCreators.js action目录

      • actionTypes.js action type目录

      • index.js redux入口文件,生成store

      • reducer.js redux逻辑文件,编写各个action所对应的逻辑

    • index.js react项目入口文件

    • TodoList.js 组件

  • package.json

  • README.md

文件细节

src目录

index.js

 import React from 'react';
 import ReactDOM from 'react-dom';
 import { Provider } from 'react-redux'
 import TodoList from './TodoList'
 import store from './store'
 ​
 ReactDOM.render(
   <React.StrictMode>
     <Provider store={store}>
       <TodoList />
     </Provider>
   </React.StrictMode>,
   document.getElementById('root')
 );
  • index.js作为整个react项目的入口文件,负责将组件挂载到#root上。挂载过程须引入React, ReactDOM。

  • render函数传入两个参数,第一个为需要被挂载的组件,第二个为挂载位置。

  • 挂载组件中Provider包括的组件共享同一个store,由store属性指定。其中Provider和store需要引入。

  • 被挂载的组件放置在Provider中,如TodoList。需引入。

TodoList.js

得益于react-redux,TodoList组件大致分为两部分,即逻辑部分与UI部分。通过connect函数连接在一起。

逻辑部分

 import { buttonClickAction, inputChangeAction, itemClickAction } from './store/actionCreators';
 ​
 const stateToProps = (state) => {
     return {
         inputValue: state.inputValue,
         list: state.valueList
     }
 }
 ​
 const dispatchToProps = (dispatch) => {
     return {
         handleInputChange(e){
             const value = e.target.value
             const action = inputChangeAction(value)
             dispatch(action)
         },
         handleButtonClick(){
             const action = buttonClickAction()
             dispatch(action)
         },
         handleLiClick(index){
             const action = itemClickAction(index)
             dispatch(action)
         }
     }
 }

逻辑部分为两个函数,定义属性的stateToProps和定义方法的dispatchToProps

stateToProps

接收一个参数state,返回一个props对象。其即为UI部分接收到的props属性。

这样做目前能发现的一个好处还有不需要再进行store的subscribe操作进行订阅更新。

dispatchToProps

接收一个参数dispatch,返回一个对象,其中包括所有方法。

在每个方法中,会先通过定义在actionCreators中的函数生成action,随后将action传入dispatch中。dispatch会将action传至reducer中进行处理。

UI部分

 import React from 'react';
 import {connect} from 'react-redux'
 ​
 const TodoList = (props) => {
     const {inputValue, list, handleInputChange, handleButtonClick, handleLiClick} = props
     return (
         <div>
             <div>
                 <input value={inputValue} onChange={handleInputChange}></input>
                 <button onClick={handleButtonClick}>确定</button>
             </div>
             <ul>
                 {list.map((item, index)=> (
                     <li key={index} onClick={()=>handleLiClick(index)}>{item}</li>
                 ))}
             </ul>
         </div>
     )
 }
 ​
 export default connect(stateToProps, dispatchToProps)(TodoList)

UI部分可以简写成无状态组件,即一个函数。函数接收的props即我们在stateToProps与dispatchToProps中返回对象的合并。我们可以先通过解构赋值来简便我们的编写操作。随后即可直接调用props中的方法。

使用connect函数将两个toProps函数与UI组件结合即可实现react-redux的功能。

store目录

store目录为redux的工作目录,与是否安装react-redux插件无关。

actionTypes.js

 export const INPUT_CHANGE = 'inputChange'
 export const BUTTON_CLICK = 'buttonClick'
 export const ITEM_CLICK = 'itemClick'

一般来讲我们需要把所有用到的action type放到一个文件中,并为每一个type定义一个常量。这样做的好处一个是方便集中管理,再一个是可以避免编写错误导致的不显示在控制台的错误。

actionCreators.js

 import { BUTTON_CLICK, INPUT_CHANGE, ITEM_CLICK } from "./actionTypes"
 ​
 export const inputChangeAction = (value) => ({
     type: INPUT_CHANGE,
     value
 })
 ​
 export const buttonClickAction = () => ({
     type: BUTTON_CLICK
 })
 ​
 export const itemClickAction = (index) => ({
     type: ITEM_CLICK,
     index
 })

其次,我们需要将用于生成action的函数放到一个文件中。在不使用中间件的情况下,action必须为一个对象,即这个文件中的每一个函数都要返回一个对象。对象的type即我们在actionTypes中定义的常量。对象的其他属性取决于我们的需要。

index.js

 import {createStore} from 'redux'
 import reducer from './reducer'
 ​
 const store = createStore(
     reducer
 )
 ​
 export default store

即redux的入口文件。引入一个createStore和我们书写的reducer。暴露出一个createStore生成的对象。其第一个参数为reducer,后面可以添加中间件如redux-thunk或redux-saga。有关中间件的知识我会放到下次进行总结。

reducer.js

 import { BUTTON_CLICK, INPUT_CHANGE, ITEM_CLICK } from "./actionTypes"
 ​
 const defaultState = {
     inputValue: 'writting something',
     valueList: ['1','2']
 }
 ​
 const reducer = (state=defaultState, action) => {
     switch (action.type){
         case INPUT_CHANGE:
             let newState = JSON.parse(JSON.stringify(state))
             newState.inputValue = action.value
             return newState
         case BUTTON_CLICK:
             console.log(BUTTON_CLICK)
             return state
         case ITEM_CLICK:
             console.log(action.index)
             return state
         default:
             return state
     }
 }
 export default reducer

即redux的逻辑部分,包含两部分,state的默认值和reducer函数。

其中reudcer函数接收两个参数,第一个为当前的state值,第二个为dispatch的action。函数会通过switch根据action.type的不同采取不同的逻辑。

需要注意的有两点,其一是reducer必须为纯函数,即禁止在其中通过axios等获取其他值,要保证返回的数据与传入的数据相对应,即如果两次传入的数据相同,则两次返回的结果也应该相同。其二为在处理逻辑时不要更改原来的state的值,可以通过深拷贝来生成一个newState变量来进行操作。

如果action.type没有被匹配到,则会返回传入的state值。

结语

一直听说react有一个很难理解的redux。让我在学习之前充满了忐忑。感谢技术胖,可以说是让我毫不费力的入门了redux。传闻中中redux的好处在于避免了各层组件中state的层层传递,不过其实因为项目比较小的缘故还并没有搞懂其中具体的好处。

但react-redux插件确实让我感受到了不少的便利。逻辑与UI的分离让项目的耦合性更低,一方面使得项目的结构更加1鲜明,另一方面也增加了项目更改时的效率。

其实本次学习中感觉收获最大的是对于项目结构的理解。从一开始觉得把type和actioncreator放在单独的文件中然后来回导入导出的麻烦,到后来的的确确发现这样微小的麻烦可以避免更多的大麻烦。可能这也是让我感觉react-redux非常便利的原因之一吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值