react

105 阅读3分钟

从0搭建react框架项目之redux配置

src/modle/index.js

import React, { Component } from 'react';
import { connect } from "react-redux";
import { bindActionCreators } from 'redux';
import store from "./../../store";
import {
    action,
} from './reducer.js'


class Index extends Component {
    constructor(props) {
        super(props);
        this.state = store.getState();
    }
    render() {
        const {
            action: {
                add_list,
                change_input,
            },
            index: {
                inputValue,
                list,
            },
        } = this.props
        return (
            <div>
                <div>
                    <input type="text" style={{ height: '17px' }}
                        value={inputValue}
                        onChange={e => change_input(e.target.value)} />
                    {/* action(add_list) 可直接用add_list() */}
                    <button style={{ verticalAlign: 'middle' }} onClick={() => add_list()}>添加</button>
                </div>

                <div>
                    <ul>
                        {list.map((item, index) => {
                            return (<li key={item + index}>{item}</li>);
                        })}
                    </ul>
                </div>
            </div>
        );
    }
}
export default connect(
    state => ({
        index: state.index,
    }),
    dispatch => ({
        action: bindActionCreators(action, dispatch),
    })
)(Index)

首先创建一个Index组件,举了个小荔枝,大致效果如下图。 image.png

其中输入框的值inputValue、列表list这两个数据是存放在key为index的reducer中的。 组件要想拿到state中的数据,需要在最外层的容器中把所有内容裹在Provider组件中,然后将之前创建的store作为prop传给Provider。

//src/index.js
const App = () => {
  return (
    <Provider store={store}>
      <Comp/>
    </Provider>
  )
};

Provider组件内的任何一个组件,(比如这里的index组件),如果需要使用state中的数据,就必须是被connect过后的组件。 connect(mapStateToProps, mapDispatchToProps, mergeProps, options)它接收四个参数,通常我们只用到前面两个,想深入了解的朋友可以去官网look look。connect的第一个参数mapStateToProps函数,这个函数允许我们把state中的数据作为props绑定到组件上。 因为我们组件用到的只有state.index中的数据所以我们只需要输出组件需要的index的数据。

const mapStateToProps = (state) => {
 return {
   index: state.index,
 }
}

connect的第二个参数是mapDispatchToProps,这个函数是将action作为props绑定到index组件上。

const mapDispatchToProps = dispatch => ({
        action: bindActionCreators(action, dispatch),
    })

本质上要触发action就必须在store上调用dispatch方法,但是为了不让index组件感知到dispatch的存在,该方法已经过包装,即调用该方法就会触发dispatch,如上述调用add_list这个action时 可直接用add_list()。 bindActionCreators函数可以自动把多个action创建函数绑定到dispatch()方法上。上述我们通过import {action} from './reducer.js' 把reducer.js中的change_input和add_list两个action同时绑定到dispatch()上。

src/module/index/reducer.js

import {
    handleActions,
    createAction,
} from 'redux-actions'
const init_state = {
    inputValue: '',
    list: [
        '睁眼起床',
        '下床刷牙',
        '穿衣出门',
    ],
}
const index_setter = createAction('index_setter')
// 隐射关系把原来的state映射成组件中的props属性
export const action = {
    change_input: payload => (dispatch, get_state) => {
        dispatch(
            index_setter({
                inputValue: payload,
            })
        )
    },
    add_list: payload => (dispatch, get_state) => {
        const state = get_state()
        const module_state = state['index']
        let list = module_state.list
        list.push(module_state.inputValue)
        dispatch(
            index_setter({
                list: list,
                inputValue: '',
            })
        )
    }
}
export default handleActions({
    [index_setter]: (state, { payload }) => ({
        ...state,
        ...payload,
    }),
}, init_state)

使用createAction创建一个index

src/reducer.js

import {
    combineReducers,
} from 'redux'
import index from './module/index/reducer'
import second from './module/second/reducer'

const app_reducer = combineReducers({ //整合所有的reducer
    index,
    second, //本次例子中没有提到,如果是直接复制过去报错,就注释掉这个reducer呀。
})
const rootReducer = (state, action) => {
    return app_reducer(state, action)
}
export default rootReducer

src/store.js

import {
    createStore,
    applyMiddleware,
} from 'redux'
import rootReducer from './reducer.js'; // 相当于仓库管理员
import thunk from 'redux-thunk'
import logger from 'redux-logger'
const env = 'development' // development production //测试环境
let enhancer
if (env === 'production') {
    enhancer = applyMiddleware(thunk)
} else {
    enhancer = applyMiddleware(thunk, logger)
}
const store = createStore(rootReducer,{}, enhancer) //创建一个store
export default store

src/router.js 配置路由

import React, {
    Component,
} from 'react'
import {
    HashRouter,
    Route,
    Redirect,
} from 'react-router-dom'
import loadable from 'react-loadable'
// import Index from './module/index'
import Second from './module/second'
const Index = loadable({
    loader: () => import('./module/index'),
    loading() {
        return <div>正在加载</div>
    },
})
class Router extends Component {
    render() {
        return (
            <HashRouter>
                <Route exact path='/' render={() => <Redirect to='/home'/>}/>
                <Route path='/home' component={Index}/>
                <Route path='/second' component={Second}/>
            </HashRouter>
        )
    }
}
export default Router

src/index.js 项目入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from "react-redux"; // 引入Provider组件
import store from "./store";
import Root from './router'

ReactDOM.render(
  <Provider store={store}>
    <Root />
  </Provider>,
  document.getElementById('root')
)