从0搭建react框架项目之redux配置
最近在整理项目的时候,从头把整个react项目的搭建顺了一遍,本文是redux、路由的配置,复制代码即可使用。
首先创建一个react项目(my-app)
然后安装一系列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
组件,举了个小荔枝,大致效果如下图。
其中输入框的值inputValue
、列表list
这两个数据是存放在key为index
的reducer中的。组件要想拿到state中的数据,需要在最外层的容器中把所有内容裹在Provider组件
中,然后将创建的store(store的创建在下面,往下看)作为this.props
传给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
作为this.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_setter,返回一个action工厂。handleActions
函数:处理action的操作,返回一个reduce。接收三个参数,第一个参数是action工厂,即index_setter;第二个参数是改变store的state的函数,大家不要被{[index_setter]:(){}}
的写法吓住,就是把属性写成变量了而已;第三个参数是当store的state啥也没有的时候给定一个初始的state。
var reducer = handleActions({
[index_setter]: (state, { payload }) => ({
...state,
...payload,
}),
}, init_state)
src/reducer.js
import {
combineReducers,
} from 'redux'
import index from './module/index/reducer'
import second from './module/second/reducer'
const app_reducer = combineReducers({
index,
//second, //本次例子中没有提到这个reducer。
})
const rootReducer = (state, action) => {
return app_reducer(state, action)
}
export default rootReducer
combineReducers
函数作用是整合所有的reducer。我们的store只有一个,而reducer可以有很多个,他们通过key值(即上面的index、second)来区分,各自的reducer服务于自己的state。
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
- 使用
createStore()
创建一个store商店,createStore接收三个参数,第一个是reducer,第二个是初始值state,第三个是中间插件enhancer。applyMiddleware()
接收多个中间插件,并返回一个enhancer函数。 - logger中间插件可以在浏览器中console打印出我们的state变化,以及整个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
- 路由配置很好理解啦,按照官网一步步配置就OK了。上面引入index组件我用到的
react-loadable
去引入,loadable
是一个高阶组件,用来轻易的在组件层里面拆分bundle,我们试想一下,一个庞大的项目,会由很多个组件组成,加载js的速度也会变慢,所以我们可能会在某个重要的组件使用异步加载,加载组件之前先让用户知道你正在加载中,组件加载成功之后再渲染组件,很好的避免了打开页面会白屏一段时间。 Redirect组件
的作用是重定向,exact
是完全匹配,即路由完全一致时才会去加载该组件。
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')
)
最后进行入口文件的配置引入就OK啦。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!