最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 记录一下redux和@connect装饰器的基本用法

    正文概述 掘金(北孤清茶)   2021-04-22   392

    首先第一步利用脚手架创建一个项目,命令是:create-react-app my_redux

    接着安装redux,命令:npm install --save redux react-redux redux-thunk

    Redux有三大原则

    单一数据源

    整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

    State 是只读的

    唯一改变 state 的方法就是触发 actionaction 是一个用于描述已发生事件的普通对象。

    使用纯函数来执行修改

    为了描述 action 如何改变 state tree ,我们需要编写 reducer

    接下来我们删除src下多余文件,只留下app.jsindex.js,创建store文件夹,并创建我们需要的js文件,此时src目录下应该是这些文件

    |-- src
    |  |-- store
    |  |  |-- index.js
    |  |  |-- reducer.js
    |  |  |-- action.js
    |  |-- index.js
    |  |-- app.js
    

    以todoList为例

    使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。
    action.js

    //把需要操作的方法导出去
    export const addTodo = (data) => {
      return dispatch => {
        //告诉reducer类型,reducer根据不同的类型做不同的操作
        dispatch({ type: 'ADD_TODO', data })
      }
    }
    export const delTodo = (index) => {
      return dispatch => {
        dispatch({type : 'DEL_TODO',index})
      }
    }
    

    reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。刚开始你可以只有一个 reducer,随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务。
    reduce.js

    //创建唯一的初始化state,如果初始化元素比较多可以单独创建state.js方便管理
    const initState = {
      todoList : ['早上五点钟起床','锻炼身体一小时','做饭吃饭']
    }
    
    //编写reducer根据不同的类型做不同的操作修改state
    const reducer = (state = initState,action) =>{
      //state是只读,所以每次修改都返回一个新的state
      let newState = JSON.parse(JSON.stringify(state))
      switch(action.type){
        case 'ADD_TODO':
          newState.todoList.push(action.data);
          return newState;
        case 'DEL_TODO':
          newState.todoList.splice(action.index,1);
          return newState;
        default:
          return newState;
      }
    }
    
    export default reducer
    

    创建store实例
    store -> index.js

    // applyMiddleware: redux通过该函数来使用中间件
    // createStore: 用于创建store实例
    import {createStore,applyMiddleware} from 'redux'
    //thunk中间件可以支持异步action
    import thunk from 'redux-thunk'
    import reducer from './reducer'
    const store = createStore(reducer,applyMiddleware(thunk))
    export default store
    

    至此,我们已经完成了所有使用Redux的准备工作,接下来就在React组件中使用Redux
    首先编写入口文件index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    //// 引入创建好的store实例
    import store from './store'
    // Provider是react-redux两个核心工具之一,作用:将store传递到每个项目中的组件中
    import {Provider} from 'react-redux'
    
    ReactDOM.render(
      <Provider store={store}>
        {/* 将store作为prop传入,即可使应用中的所有组件使用store */}
        <App />
      </Provider>,
      document.getElementById('root')
    );
    

    最后app.js

    import React, { Component } from 'react'
    // connect方法的作用:将额外的props传递给组件,并返回新的组件,组件在该过程中不会受到影响
    import { connect } from 'react-redux'
    // 引入action
    import {addTodo,delTodo} from './store/action'
    class App extends Component {
      state = {
        value : ''
      }
      changeValue = (e) =>{
        this.setState({
          value : e.target.value,
        })
      }
      addTodoFn = () =>{
        //触发addTodo添加备忘的action
        this.props.addTodo(this.state.value)
        this.setState({
          value :''
        })
      }
      delTodoFn = (index) =>{
        //触发delTodo删除备忘的action
        this.props.delTodo(index)
      }
      render() {
        return (
          <div>
            <ol>
              {this.props.todoList.map((item,index)=>(
                <li key={index} onClick={this.delTodoFn.bind(this,index)}>{item}</li>
              ))}
            </ol>
            <input type="text" value={this.state.value} onChange={this.changeValue}/>
            <button onClick={this.addTodoFn}>添加</button>
          </div>
        )
      }
    }
    // mapStateToProps:将state映射到组件的props中
    const mapStateToProps = (state) => ({
      todoList : state.todoList
    })
    // mapDispatchToProps:将action里的dispatch映射到组件的props中
    const mapDispatchToProps = {
      addTodo,
      delTodo
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(App)
    
    

    @connect装饰器

    装饰器可以让代码写起来更顺手,看起来也简洁一点,

    1. 在命令行执行命令 npm run eject。如果报错的信息大概意思是:有些文件未被追踪到,那么直接git add .git commit -m"",或者直接在.gitignore中忽略这些文件(不建议);
    2. 之后package.json中会出现很多依赖建议yarn/npm i 一下,防止网速不好出现丢包现象;
    3. 然后打开package.json文件,找到"babel"开头的一个对象,(一般在最后,),这是原始的样子:
    "babel": {
        "presets": [
          "react-app"
        ]
      }
    

    加入另外一项:

    "babel": {
        "presets": [
          "react-app"
        ],
        "plugins": [
          [
            "@babel/plugin-proposal-decorators",
            {
              "legacy": true
            }
          ]
        ]
      }
    

    最后重启项目就可以了,一定要重启项目不然可能会报错Support for the experimental syntax 'decorators-legacy' isn't currently enabled (6:1):
    然后就可以使用@conncet装饰器了,把app.js可以修改如下:

    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    import {addTodo,delTodo} from './store/action'
    //直接在class上一行,接收两个参数,跟之前的写法差不多,第一个参数是需要用的state,第二个参数是需要用的action
    @connect(state=>({
      todoList : state.todoList
    }),{addTodo,delTodo})
    class App extends Component {
      state = {
        value : ''
      }
      changeValue = (e) =>{
        this.setState({
          value : e.target.value,
        })
      }
      addTodoFn = () =>{
        //触发addTodo添加备忘的action
        this.props.addTodo(this.state.value)
        this.setState({
          value :''
        })
      }
      delTodoFn = (index) =>{
        //触发delTodo删除备忘的action
        this.props.delTodo(index)
      }
      render() {
        return (
          <div>
            <ol>
              {this.props.todoList.map((item,index)=>(
                <li key={index} onClick={this.delTodoFn.bind(this,index)}>{item}</li>
              ))}
            </ol>
            <input type="text" value={this.state.value} onChange={this.changeValue}/>
            <button onClick={this.addTodoFn}>添加</button>
          </div>
        )
      }
    }
    //用@connect装饰器一定要以这种方式导出,不然报错,具体什么原因我还没找到
    export default App
    
    

    调试工具插件

    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    在redux中添加这个插件是在chrome浏览器可以看到state的每一步流程,更加清晰,在store下index.js中添加修改

    import {createStore,applyMiddleware,compose} from 'redux'
    import thunk from 'redux-thunk'
    import reducer from './reducer'
    const composeEnhancers =
      typeof window === 'object' &&
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
          // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
        }) : compose;
    
    const enhancer = composeEnhancers(
      applyMiddleware(thunk),
      // other store enhancers if any
    );
    const store = createStore(reducer, enhancer);
    export default store
    

    记录一下redux和@connect装饰器的基本用法


    下载网 » 记录一下redux和@connect装饰器的基本用法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元