zoukankan      html  css  js  c++  java
  • redux 存值 及 取值 的操作

    项目目录

    首先,一个基于React + Redux + React-Router的项目目录可以按照我下方的图片来构建:

    其中assets目录用于存放项目的静态资源,如css/图片等,src目录则用于存放React的组件资源。

    入口文件配置

    在webpack的配置项中,我们需要一个或多个入口文件,这里我就不展示关于package.json及webpack.config.js的文件配置,最后我会提供整个项目的下载链接供大家参考。这里我主要介绍下入口文件index.js的配置说明。

    import React from 'react'  // 引入React
    import { render } from 'react-dom' // 引入render方法
    import { Provider } from 'react-redux' // 利用Provider可以使我们的 store 能为下面的组件所用
    import { Router, browserHistory } from 'react-router' // Browser history 是由 React Router 创建浏览器应用推荐的 history
    import { syncHistoryWithStore } from 'react-router-redux' // 利用react-router-redux提供的syncHistoryWithStore我们可以结合store同步导航事件
    
    import finalCreateStore from './src/store/configureStore'  //引入增强后的store
    import DevTools from './src/containers/DevTools'  // 引入Redux调试工具DevTools
    import reducer from './src/reducers'  // 引入reducers集合
    import routes from './src/routes'   // 引入路由配置
    
    import './assets/css/bootstrap.min.css'  // 引入样式文件
    
    // 给增强后的store传入reducer
    const store = finalCreateStore(reducer)
    
    // 创建一个增强版的history来结合store同步导航事件
    const history = syncHistoryWithStore(browserHistory, store)
    
    render(
        {/* 利用Provider包裹页面 */}
        <Provider store={store}>
            <div>
                {/* 渲染根路由 */}
                <Router history={history} routes={routes} />
                {/* 渲染调试组件 */}
                <DevTools />
            </div>
        </Provider>,
        document.getElementById('mount')
    )

    在入口文件中我们尽量只需要保留基本的东西,其余的配置代码我们可以放到相应的配置文件中去,比如路由、reducers及store的配置等。这里我都把它们放置到了独立的js中,只在入口文件中通过import引入,这样管理和维护起来会非常方便,但也会相应增加理解的难度,然而一旦上手就会很容易。那么接下来我们再来看下store配置吧。

    store配置

    import thunk from 'redux-thunk' // redux-thunk 支持 dispatch function,并且可以异步调用它
    import createLogger from 'redux-logger' // 利用redux-logger打印日志
    import { createStore, applyMiddleware, compose } from 'redux' // 引入redux createStore、中间件及compose 
    import DevTools from '../containers/DevTools' // 引入DevTools调试组件
    
    // 调用日志打印方法
    const loggerMiddleware = createLogger()
    
    // 创建一个中间件集合
    const middleware = [thunk, loggerMiddleware]
    
    // 利用compose增强store,这个 store 与 applyMiddleware 和 redux-devtools 一起使用
    const finalCreateStore = compose(
        applyMiddleware(...middleware),
        DevTools.instrument(),
    )(createStore)
    
    export default finalCreateStore

    这里我们需要了解中间件(Middleware)的概念。middleware 是指可以被嵌入在框架接收请求到产生响应过程之中的代码,你可以在一个项目中使用多个独立的第三方 middleware,如上面的redux-thunk和redux-logger。详细资料请参考官方文档:
    http://cn.redux.js.org/docs/advanced/Mid...

    路由配置

    上面的入口文件配置中我们把路由配置部分单独放到了routes.js的文件中,这里我们就来看下其配置:

    import React from 'react' // 引入react
    import { Route, IndexRoute } from 'react-router' // 引入react路由
    import { App, Home, Foo, Bar, Antd } from './containers' // 引入各容器组件
    
    export default (
        <Route path="/" component={App}>
            <IndexRoute component={Home}/>
            <Route path="index" component={Home}/>
            <Route path="foo" component={Foo}/>
            <Route path="bar" component={Bar}/>
            <Route path="antd" component={Antd}/>
        </Route>
    )

    这里的路由配置和不使用redux时候是一样的,唯一需要了解的是容器组件和展示组件的概念。上面配置文件中的路由加载的组件都可以认为是容器组件。
    (1)顾名思义,展示组件包含在容器组件中,只用作页面展示,不会定义数据如何读取如何改变,只通过this.props接受数据和回调函数;
    (2)而容器组件中包含各展示组件的数据,即Props,它们为展示组件或其他组件提供数据和方法。
    我们应该把它们放在不同的文件夹中,以示区别,如上面“项目目录”中的containers和components文件夹分别存放容器组件和展示组件。具体说明可以参考文章:http://www.jianshu.com/p/6fa2b21f5df3

    根组件配置

    import React, { Component } from 'react' // 引入React
    import { Link } from 'react-router' // 引入Link处理导航跳转
    
    export default class App extends Component {
        render() {
            return(
                <div>
                    <nav className="navbar navbar-default">
                        <div className="container-fluid">
                            <div className="navbar-header">
                                <span className="navbar-brand" href="#">
                                    <Link to="/">Redux</Link>
                                </span>
                            </div>
                            <ul className="nav navbar-nav">
                                <li>
                                    <Link to="/index" activeStyle={{color: '#555', backgroundColor: '#e7e7e7'}}>计数器</Link>
                                </li>
                                <li>
                                    <Link to="/foo" activeStyle={{color: '#555', backgroundColor: '#e7e7e7'}}>静态数据</Link>
                                </li>
                                <li>
                                    <Link to="/bar" activeStyle={{color: '#555', backgroundColor: '#e7e7e7'}}>动态数据</Link>
                                </li>
                                <li>
                                    <Link to="/antd" activeStyle={{color: '#555', backgroundColor: '#e7e7e7'}}>结合antd</Link>
                                </li>
                            </ul>
                        </div>
                    </nav>
                    <div className="panel panel-default">
                        <div className="panel-body">
                            { this.props.children }
                        </div>
                    </div>
                </div>
            )
        }
    }

    整个根组件App.js主要渲染了整个应用的导航和可变区域,这其实和Redux没有关系。需要注意的是to中的URL地址需要和routes.js中的path地址名称一致。

    写到这里还没有介绍Redux中的Action及Reducer的配置,那么接下来就来介绍下。

    Action配置

    import { INCREASE, DECREASE, GETSUCCESS, REFRESHDATA } from '../constants'  // 引入action类型名常量
    import 'whatwg-fetch'  // 可以引入fetch来进行Ajax
    
    // 这里的方法返回一个action对象
    export const increase = n => {
        return {
            type: INCREASE,
            amount: n
        }
    }
    
    export const decrease = n => {
        return {
            type: DECREASE,
            amount: n
        }
    }
    
    export const refreshData = () => {
        return {
            type: REFRESHDATA
        }
    }
    
    export const getSuccess = (json) => {
        return {
            type: GETSUCCESS,
            json
        }
    }
    
    function fetchPosts() {
        return dispatch => {
            return fetch('data.json')
                .then((res) => { console.log(res.status); return res.json() })
                .then((data) => {
                    dispatch(getSuccess(data))
                })
                .catch((e) => { console.log(e.message) })
            }
    }
    
    // 这里的方法返回一个函数进行异步操作
    export function fetchPostsIfNeeded() {
    
        // 注意这个函数也接收了 getState() 方法
        // 它让你选择接下来 dispatch 什么
        return (dispatch, getState) => {
            return dispatch(fetchPosts())
        }
    }

    上面返回一个action对象的方法叫做“action 创建函数”,它就是生成action的方法,也是store数据的唯一来源。
    上面返回一个函数的方法叫做“异步action”,这里使用的是Redux Thunk middleware,要引入redux-thunk这个专门的库才能使用,这样我们就可以实现异步Ajax请求改变状态等功能了。

    Reducer配置

    reducers/count.js
    // reducers/count.js
    import { INCREASE, DECREASE, GETSUCCESS, REFRESHDATA } from '../constants' // 引入action类型常量名
    
    // 初始化state数据
    const initialState = {
        number: 1,
        lists: [
            {text: '整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。'}, 
            {text: '惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。'},
            {text: '为了描述 action 如何改变 state tree ,你需要编写 reducers。'},
            {text: '就是这样,现在你应该明白 Redux 是怎么回事了。'}
        ],
        data: []
    }
    
    // 通过dispatch action进入
    export default function update(state = initialState, action) {
    
        // 根据不同的action type进行state的更新
        switch(action.type) {
            case INCREASE:
                return Object.assign({}, state, { number: state.number + action.amount })
                break
            case DECREASE:
                return Object.assign({}, state, { number: state.number - action.amount })
                break
            case GETSUCCESS:
                return Object.assign({}, state, { data: action.json })
            case REFRESHDATA:
                return Object.assign({}, state, { data: [] })
            default:
                return state
        }
    }
    reducers/index.js
    // reducers/index.js
    import { combineReducers } from 'redux' // 利用combineReducers 合并reducers
    import { routerReducer } from 'react-router-redux' // 将routerReducer一起合并管理
    import update from './count' // 引入update这个reducer
    
    export default combineReducers({
        update,
        routing: routerReducer
    })

    这里我们主要需要了解如何通过combineReducers来合并reducers,同时在进入reducer方法后我们必须返回一个state的处理结果来更新state状态,否则会报错。还需注意的是在合并reducers的时候,需要加上routerReducer这个由“react-router-redux”提供的reducer来管理路由的状态更新。

    容器组件

    上文提到了容器组件和展示组件的区别和含义,这里我们需要在容器组件使用connect来搭配Redux来进行状态管理,这是很关键的一步。

    import React, { Component, PropTypes } from 'react' // 引入React
    import { connect } from 'react-redux' // 引入connect 
    import List from '../components/List'  // 引入展示组件List
    
    export default class Foo extends Component {
        render() {
        
            // 通过this.props获取到lists的值
            const { lists } = this.props
    
            return(
                <div>
                    <ul className="list-group">
                        {将值传入展示组件}
                        { lists.map((e, index) => 
                            <List text={e.text} key={index}></List>
                        )}
                    </ul>
                </div>
            )
        }
    }
    
    // 验证组件中的参数类型
    Foo.propTypes = {
        lists: PropTypes.arrayOf(PropTypes.shape({
            text: PropTypes.string.isRequired
        }).isRequired).isRequired
    }
    
    // 获取state中的lists值
    const getList = state => {
        return {
            lists: state.update.lists
        }
    }
    
    // 利用connect将组件与Redux绑定起来
    export default connect(getList)(Foo)

    在容器组件中我们需要获取state中的初始状态的时候,我们需要使用connect。任何一个从 connect() 包装好的组件都可以得到一个 dispatch 方法作为组件的 props,以及得到全局 state 中所需的任何内容。connect() 的唯一参数是 selector。此方法可以从 Redux store 接收到全局的 state,然后返回组件中需要的 props。详资料请参考文档:http://cn.redux.js.org/docs/basics/Usage...

    展示组件

    上面的容器组件中引入了一个展示组件List,我们来看下它的代码:

    import React, { Component, PropTypes } from 'react'
    
    export default class List extends Component {
        render() {
            return(
                <li className="list-group-item">{this.props.text}</li>
            )
        }
    }
    
    List.propTypes = {
        text: PropTypes.string.isRequired
    }

    从中我们可以发现,展示组件没有connect的方法,数据是通过this.props来获取的,这样的方式能够是数据的变化清晰可查,便于管理和维护。

  • 相关阅读:
    codeforces 701 D. As Fast As Possible(数学题)
    codeforces 807 E. Prairie Partition(贪心+思维)
    codeforces 807 D. Dynamic Problem Scoring(贪心+思维)
    codeforces 807 C. Success Rate(二分)
    Atcoder C
    Atcoder D
    hdu 3308 LCIS(线段树区间合并)
    SpringMVC学习笔记---
    Composer Yii2 不设置全局变量 归档安装 Win7
    电脑硬件扫盲--CPU 显卡
  • 原文地址:https://www.cnblogs.com/crazycode2/p/8655338.html
Copyright © 2011-2022 走看看