配置步骤(一):http://blog.csdn.net/cbboke31/article/details/75950094
配置步骤(二): http://blog.csdn.net/cbboke31/article/details/76043356
这里先讲每一步的原因和做法。配置步骤(四)会讲怎么快速搭建webpack,同时会把整个项目包分享到git上。
目录
四、React 配置
1. React 组件
2. React router 模块
3. React 和Redux 配合
在前面的文章已经讲解怎么配置好了整个webpack环境。后面会有一篇文章讲怎么快速搭建webpack。
1. React 组件
先用node.js安装react 和react-dom 模块:
npm install react react-dom --save
在webpack.dll.config.js 里面的vendors 数组里面添加 react-dom 第三库
const vendors = [
'react',
"react-dom"
];
在Powershell 窗口里面敲下面指令,把第三方库打包到dll里面。
webpack -p --config webpack.dll.config.js --progress --profile --colors
指令完成后,会更新manifest.json 和vendor.xxxx.js。 这时需要手动刷新html 模板里面引进的vendor.xxxx.js文件。
修改app.js里面的内容,添加reactdom 的渲染语句:
require('./css/css');
require('./less/less.less');
require('./scss/scss.scss');
var app=document.createElement("div");
app.innerHTML='Hello World!
';
document.body.insertBefore(app,document.body.childNodes[0]);
//下面的是react的代码
import React from 'react';
import ReactDOM from 'react-dom';
class FirstComponent extends React.Component{
render(){
return(
<div>
this is React code from Components.
div>
);
}
}
var div=document.createElement("div");
div.setAttribute("id","root");
document.body.insertBefore(div,document.body.childNodes[1]);
ReactDOM.render( ,document.getElementById('root'));
在powershell里面敲npm start 启动服务器,在浏览器上敲localhost:8080 就可以显示这个网页的内容。
2.React router 模块
先安装相应的模块:react-router-dom,指令:
npm install react-router-dom --save
这个模块同样需要添加到webpack.dll.config.js 里面的vendors 数组里面添加 react-dom 第三库
const vendors = [
'react',
"react-dom"
];
在Powershell 窗口里面敲下面指令,把第三方库打包到dll里面。
webpack -p --config webpack.dll.config.js --progress --profile --colors
指令完成后,会更新manifest.json 和vendor.xxxx.js。 这时需要手动刷新html 模板里面引进的vendor.xxxx.js文件。
修改app.js里面的内容:
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink,Route,BrowserRouter,HashRouter as Router, Swith,Redirect} from 'react-router-dom';
import RouteConfig from '../Config/Route.jsx';
var div=document.createElement("div");
div.setAttribute("id","root");
document.body.insertBefore(div,document.body.childNodes[1]);
ReactDOM.render(
{RouteConfig}
,document.getElementById('root'));
现在的router 有两个版本,用react-router 或者react-router-dom 。这里用react-router-dom,这个模块有几个接口:NavLink 、Route 、BrowserRouter、HashRouter、Swith、Redirect 等 。每个接口的作用我这不做说明。RouteConfig 是路由配置文件,自己创建的。
现在需要创建几个文件,
1) 在根目录创建Config文件夹,文件夹里面创建Route.jsx。
Route.jsx 的内容:
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink,Route,BrowserRouter as Router,HashRouter,Switch,Redirect} from 'react-router-dom';
import MainComponent from '../component/Main.jsx';//引进组件
import Topic from '../component/Topic.jsx';//引进组件
const routes =[
{
path:'/',
exact:true,
component: MainComponent
},
{
path:'/topic',
exact:false,
component:Topic
},
];
const RouteConfig = (
{
routes.map((route,index)=>(
))
}
);
export default RouteConfig;
2)在根目录下创建component 文件夹,文件夹下创建两个文件:
Main.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink as Link} from 'react-router-dom';
class MainComponent extends React.Component{
render(){
return(
mainText
"/topic">jumpe to Topic
);
}
}
export default MainComponent;
Topic.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink as Link} from 'react-router-dom';
class Topic extends React.Component{
render(){
return(
topicText:
"/">jumpe to Main
);
}
}
export default Topic;
建完后,在powershell窗口下敲npm start,然后在浏览器地址栏敲localhost:8080 就后出现下面页面:
点击 jumpe to Topic ,就会跳到 topic 页面:
这样webpack react router 就这样简单的配置好了。
3.React 和Redux 配合
Redux 模块可以集中管理 react全部组件的state,这个技术很常用。
安装Redux模块,指令:
npm install redux react-redux react-router-redux redux-thunk --save
模块安装好后,在需要在webpack.dll.config.js 里面修改vendors的内容:
const vendors = [
'react',
"react-dom",
"react-router-dom",
"redux",
"react-redux",
"react-router-redux",
"redux-thunk"
];
在Powershell 窗口下,敲:
webpack -p --config webpack.dll.config.js --progress --profile --colors
在build 路径下会再次生成manifest.json 和 vendor.xxxxx.js文件,把相应的vendor.xxxxx.js文件引入到index.html模板文件中。
要使用redux,需要先理解它的基本原理,这里我简单的说下,具体的可以百度了解下。
redux 主要分为三块,store reducer action。
store 用来存储component里面需要集中管理的state;
action 是定义与state状态改变相关的一系列方法(方法也称为action creator);
reducer 初始化state及调用action的方法修改state的状态,返回新state。
这三者之间的用什么相互关联的,下面步骤讲解里面会有提及。
store 一般会采用自动创建的方法。react组件可以通过函数直接上传给store,上传代码是直接写在组件里面,不需要添加一个组件就修改一次store的代码。
store 的中间件用来实现异步调用,这里用ReduxThunk。这个中间件的优缺点,暂时不涉及。
在src 目录下创建一个Config 文件夹,在Config 里面新建一个Store.jsx。
Store.jsx 的代码:
import {createStore,combineReducers,applyMiddleware} from 'redux';
import RootReducer from '../Reducer/index.jsx';//引入reduce
import ReduxThunk from 'redux-thunk';//中间件
var store = createStore( //自动生成store的函数
RootReducer, //reduce,修改state状态的函数集合
applyMiddleware(ReduxThunk) //中间件
);
export default store;
RootReducer是自己定义的reduce文件。createStore applyMiddleware 来自redux 模块。 ReduxThunk 来自于redux-thunk。
store 和 reducer 是通过createStore 关联起来的。
action
在src下面创建一个action文件夹,action文件夹下新建一个action.jsx文件。
action代码:
const actions = {
changeText:function(num){
console.log("调用actions");
switch(num){
case 1:
return {type:'AlterMain',payload:"mainContainer had been changed"};
case 2:
return {type:'AlterTopic',payload:"topicContainer had been changed"};
default:
return action;
}
},
};
export default actions;
预先规划设定state格式为:
const defaultState = { //在reducer 里面定义state的初始的值
mainText:”mainContainer”,
topicText:”topicContainer”
};
action这里定义了一个修改state状态的函数。当reducer调用action时,action就会通过不同的情况返回不同的action值。
reducer:
在src文件夹下面创建一个Reducer文件夹,文件夹下面新建一个index.jsx文件。
reducer的代码:
import {combineReducers} from 'redux';
import {routerReducer} from 'react-router-redux';
const defaultState = {//设定state的默认值
mainText:"mainContainer",
topicText:"topicContainer"
};
const reducer = (state = defaultState, action) => {
switch (action.type) {//通过action的返回值来选择更新哪个state的状态
case 'AlterMain':
return Object.assign({},state,{ mainText:action.payload});
case 'AlterTopic':
return Object.assign({},state,{ topicText:action.payload});
default:
return state;
}
};
const RootReducer = combineReducers({//可以定义多个reducer,然后通过combineReducers来合并
routing:routerReducer,//redux和router处理函数
app:reducer //app 需要与组件里面上传的state一致
});
export default RootReducer;
reducer 只看到 通过action返回值来修改state的状态并没有看到调用action。
在调试移动端显示的时候,发现object.assign 存在兼容问题,在网上查了下资料,需要额外添加下面这段代码:
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
组件的定义:
修改component文件夹下的Main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink as Link} from 'react-router-dom';
import {connect} from 'react-redux';
import P from 'prop-types';
import actions from '../src/action/action.jsx';//引入actions
//mapstoreStateToProps 这里指定Main控件需要上传的state
const mapStoreStateToProps = (state) =>(
{
mainText:state.app.mainText, //mainText是变量,值对应的state.app.mainText的存储空间,其中app与reducers里面定义的一致。
}
);
//mapDispatchToProps 这里上传处理state函数,即action里面定义的函数
const mapDispatchToProps = (dispatch,ownProps)=> ({
fn:{
changeText:(num)=> dispatch(actions.changeText(num))
}
});
//这样state一致上传到store,需要取值用props取就ok
class MainComponent extends React.Component{
render(){
return(
mainText:{this.props.mainText}
"/topic">jumpe to Topic
);
}
}
//最后调用connect函数,把组件和store连接起来
export default connect(mapStoreStateToProps,mapDispatchToProps)(MainComponent);
connect 函数能成功执行的前提是 组件是provider的子组件。所有需要修改app.js 。
app.js 代码:
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink,Route,BrowserRouter,HashRouter as Router, Swith,Redirect} from 'react-router-dom';
import RouteConfig from '../src/Config/Route.jsx';
import {Provider} from 'react-redux';
import store from '../src/Config/Store.jsx';
var div=document.createElement("div");
div.setAttribute("id","root");
document.body.insertBefore(div,document.body.childNodes[0]);
ReactDOM.render(
//Provider 并指定store的文件
{RouteConfig}
,document.getElementById('root'));
Topic.jsx的代码:
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink as Link} from 'react-router-dom';
import {connect} from 'react-redux';
import actions from '../src/action/action.jsx';
const mapStoreStateToProps = (state) =>(
{
topicText:state.app.topicText,
}
)
const mapDispatchToProps = (dispatch,ownProps)=> ({
fn:{
changeText:(num)=> dispatch(actions.changeText(num))
}
});
class Topic extends React.Component{
render(){
return(
topicText:{this.props.topicText}
"/">jumpe to Main
);
}
}
export default connect(mapStoreStateToProps,mapDispatchToProps)(Topic);
这样整个redux就搭建好了。
provider 指定 store文件,它下面的组件可以通过connect 把组件和store关联。
store:通过createStore 把 store和reducer 关联
reducer: 定义state的默认值,并定义state 和action的对应关系。combineReducers 合并reducer,指定reducer的接口,如果用到router时,要注意定义route的处理函数。
action:只是单独定义一些修改state状态的操作。
组件:通过connect 把需要集中管理的state即state对应的action 上传到store,并绑定组件。state的值被修改,组件的view就会做相应的改变
这里没有涉及到redux的异步通信。
流程可以简化理解为:
组件->action->dispath(action)->store->reducer ->store(修改state)->组件(view)
网页的整体效果如下:
用http://localhost:8080 就能看到下面的界面:
点击修改mainText的值 的按钮,mainText就会被更改如下:
点击jumpe to Topic
点击 修改topicText的值 的按钮,topicText就会被更改如下:
参考文档:
http://blog.csdn.net/lx376693576/article/details/54591142
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
http://isluo.com/work/react-luo/index.html
https://github.com/lzxb/react-cnode.git