博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
react+react-router+redux+react-redux构建一个简单应用
阅读量:7087 次
发布时间:2019-06-28

本文共 15022 字,大约阅读时间需要 50 分钟。

  hot3.png

完整的demo代码:

演示:

一.基本知识

我们已经学习了react的语法使用,react-router和react的配合使用,redux通过react-redux的结合使用,下面我们要组合起来,开发一个简单的应用。

二.应用结构

index.html(我们的单页开发核心静态页面)

index.js(应用渲染首页面)

App.js(核心页面)

rootRedux.js(合并所有状态,对外接口)

indexRedux.js(根状态树)

 

page/(目录,存放路由页面组件)

page/login/LoginReactRedux.js(登录页面组件被react-redux封装,我们的首页显示页面,需要用户登录)

page/login/Login.js(登录页面组件)

page/login/LoginRedux.js(登录页面reducer)

我们不在创建action的页面,不会去分离出去,我们的业务只是demo使用

其他路由页面构建类似...(包含登录页面,主页面,关于我们,新闻中心四个页面作为演示)

 

tpl/(目录,存放公用组件,用于路由页面公用显示使用)

 

我们的ajax处理都会利用setTimeout去模拟,同样也不使用action可以用函数的中间件,因为应用非常简单

三.创建初始化应用

利用我们的create-react-app 项目名 来创建,执行下面创建我们的demo-react应用:

create-react-app demo-react

删除一些不要的东西,让我们的项目看起来尽可能简洁:

index.html

      
React App

index.js

import React from 'react';import ReactDOM from 'react-dom';import App from './App';import registerServiceWorker from './registerServiceWorker';ReactDOM.render(
, document.getElementById('root'));registerServiceWorker();

App.js

import React, { Component } from 'react';class App extends Component {  render() {    return (      
demo
); }}export default App;

四.安装需要的依赖

我们的项目需要:

react-router:

npm install react-router

react-router-dom:(我们实际使用的路由模块)

npm install react-router-dom

redux:

npm install redux

react-redux:

npm install react-redux

等待完成...

我们的使用版本:

100646_VbqF_2352644.png

我们采用的react16.x和react-router4.x,不同的版本使用是有区别的,尤其路由使用上

五.创建目录结构和文件

100812_NFOf_2352644.png

page下存放我们路由使用的页面组件

六.创建路由页面和搭载路由

1.创建页面

这时候我们已经可以看到显示demo的页面,我们开始创建我们的页面:

login/Login.js

import React, { Component } from 'react';//=====组件=====class Login extends Component {		render() {		return (			

登录页面

用户名
密码
); } goLogin(){ alert("开始登录") } componentDidMount() { console.log("Login渲染完毕") } }export default Login

home/Home.js

import React, { Component } from 'react';//=====组件=====class Home extends Component {		render() {		return (			

主页

); } componentDidMount() { console.log("Home渲染完毕") } }export default Home

about/About.js

import React, { Component } from 'react';//=====组件=====class About extends Component {		render() {		return (			

关于我们

); } componentDidMount() { console.log("About渲染完毕") } }export default About

news/News.js

import React, { Component } from 'react';//=====组件=====class News extends Component {		constructor(props) {		super(props);		// 设置 initial state		this.state = {			list: [				{id:1,title:"a",con:"caaaaaaaaaaaaaaaa"},				{id:2,title:"b",con:"cbbbbbbbbbbb"},				{id:3,title:"c",con:"cccccccccccccc"},				{id:4,title:"d",con:"cddddddddddddd"},				{id:5,title:"e",con:"ceeeeeeeeeeee"}			]		};	}		render() {		return (			

新闻页面

    { this.state.list.map(function(item,i){ return
  • {item.title} {item.con}
  • }) }
); } componentDidMount() { console.log("News渲染完毕") } }export default News

2.搭载路由

我们把页面创建完毕,在index.js配置路由:

index.js:

import React from 'react';import ReactDOM from 'react-dom';import {BrowserRouter as Router} from 'react-router-dom';import App from './App';import registerServiceWorker from './registerServiceWorker';ReactDOM.render(	
, document.getElementById('root'));registerServiceWorker();

App.js完成我们路由和页面的使用:

App.js:

import React, { Component } from 'react';import {  Route,  Link} from 'react-router-dom';import Login from './page/login/Login.js';import Home from './page/home/Home.js';import About from './page/about/About.js';import News from './page/news/News.js';class App extends Component {  render() {    return (      
  • 登录
  • 主页
  • 关于我们
  • 新闻页面
); }}export default App;

我们预览页面,就可以看到大概了:

140338_As6o_2352644.png

七.redux和应用配合

创建我们的redux文件:

rootRedux.js(合并所有状态,对外接口):

import { combineReducers } from 'redux';//全局reducerimport isLogin from './indexRedux.js'//子reducer//合并reducervar rootRedux = combineReducers({	isLogin})export default rootRedux

indexRedux.js(根状态树)我们存放登录状态,默认是未登录:

//reducervar isLogin=false;function indexRedux(state = isLogin, action) {	switch (action.type) {		case "GO_LOGIN":			//登录			return true		case "OUT_LOGIN":			//退出登录			return false		default:		  	return state	}}export default indexRedux

index.js使用redux:

import React from 'react';import ReactDOM from 'react-dom';import {BrowserRouter as Router} from 'react-router-dom';//redux 和react-redux(关联react和redux)import { createStore } from 'redux';import { Provider } from 'react-redux';//reducers 状态树state和逻辑操作import rootRedux from './rootRedux.js'import App from './App';import registerServiceWorker from './registerServiceWorker';//创建状态树和设置//生成状态树对象const store = createStore(rootRedux);//start 状态树应用到全局 通过ProviderReactDOM.render(
, document.getElementById('root'));registerServiceWorker();

我们为news创建reducer,把list放入在reducer中,

142459_Ynl2_2352644.png

NewsRedux.js:

//reducervar newsinit={	list:[		{id:1,title:"a",con:"caaaaaaaaaaaaaaaa"},		{id:2,title:"b",con:"cbbbbbbbbbbb"},		{id:3,title:"c",con:"cccccccccccccc"},		{id:4,title:"d",con:"cddddddddddddd"},		{id:5,title:"e",con:"ceeeeeeeeeeee"}	]};function NewsRedux(state = newsinit, action) {	switch (action.type) {		case "SORT_REVERSE":			//倒叙显示			var arr=state.list;			var arr2=[];			for(var i=arr.length-1;i>=0;i--){				arr2.push(arr[i])			}			return Object.assign({},state,{list:arr2})		default:		  	return state	}}export default NewsRedux

News.js移除构造函数的json设置:

import React, { Component } from 'react';//=====组件=====class News extends Component {		constructor(props) {		super(props);	}		render() {		return (			

新闻页面

); } componentDidMount() { console.log("News渲染完毕") } }export default News

rootRedux.js引入news的reducer:

import { combineReducers } from 'redux';//全局reducerimport isLogin from './indexRedux.js'//子reducerimport NewsRedux from './page/news/NewsRedux.js'//合并reducervar rootRedux = combineReducers({	isLogin,	NewsRedux})export default rootRedux

八.利用react-redux链接react组件和redux

我们先以news的处理作为操作,首先用react-redux封装News.js组件:

创建NewsReactRedux.js:

143540_APpV_2352644.png

import { connect } from 'react-redux';//=====引入组件=====import News from './News.js'//=====react-redux 封装组件=====// 哪些 Redux 全局的 state 是我们组件想要通过 props 获取的?function mapStateToProps(state) {	return {		list: state.NewsRedux.list	};}// 哪些 action 创建函数是我们想要通过 props 获取的?function mapDispatchToProps(dispatch) {	return {		SORTREVERSE:function(){			dispatch({type:"SORT_REVERSE"})		}	};}//封装传递state和dispatchvar NewsReactRedux = connect(mapStateToProps,mapDispatchToProps)(News);export default NewsReactRedux

我们把redux的状态数据和action全部发射给News组件,我们在里面使用即可:

News.js

import React, { Component } from 'react';//=====组件=====class News extends Component {		constructor(props) {		super(props);	}		render() {		return (			

新闻页面

    { this.props.list.map(function(item,i){ return
  • {item.title} {item.con}
  • }) }
); } SORTREVERSE(){ this.props.SORTREVERSE(); } componentDidMount() { console.log("News渲染完毕") } }export default News

App.js使用封装后的组件News:

import React, { Component } from 'react';import {  Route,  Link} from 'react-router-dom';import Login from './page/login/Login.js';import Home from './page/home/Home.js';import About from './page/about/About.js';import NewsReactRedux from './page/news/NewsReactRedux.js';class App extends Component {  render() {    return (      
  • 登录
  • 主页
  • 关于我们
  • 新闻页面
); }}export default App;

九.登录处理

/地址就是我们的登录页面,我们点击登录跳转就可以了,不过我们会把用户的登录状态存放在indexRedux.js中,我们不把这个状态存如cookie类似的本地,所以 我们刷新页面退出即可,我们只是模拟的处理:

如果存放在了cookie我们要如何处理,这时候在进入网站我们可以调用一个方法去获取cookie的登录状态,不管是什么我们都会执行action把redux的登录状态改为这个!

因为Login.js要和redux结合,我们要修改登录状态,我们还要结合router去手动跳转到主页,

LoginReactRedux.js:

import { connect } from 'react-redux';//=====引入组件=====import Login from './Login.js'//=====react-redux 封装组件=====// 哪些 Redux 全局的 state 是我们组件想要通过 props 获取的?function mapStateToProps(state) {	return {}}// 哪些 action 创建函数是我们想要通过 props 获取的?function mapDispatchToProps(dispatch) {	return {		GOLOGIN:function(username,password,history){			console.log("用户名"+username)			console.log("密码"+password)			setTimeout(function(){				dispatch({type:"GO_LOGIN"})				history.push("/Home")			},1000)					}	};}//封装传递state和dispatchvar LoginReactRedux = connect(mapStateToProps,mapDispatchToProps)(Login);export default LoginReactRedux

login.js

import React, { Component } from 'react';//=====组件=====class Login extends Component {		render() {		return (			

登录页面

用户名
密码
); } goLogin(){ this.props.GOLOGIN(this.refs.username.value,this.refs.password.value,this.props.history); } componentDidMount() { console.log("Login渲染完毕") } }export default Login

App.js:

import React, { Component } from 'react';import {  Route,  Link} from 'react-router-dom';import LoginReactRedux from './page/login/LoginReactRedux.js';import Home from './page/home/Home.js';import About from './page/about/About.js';import NewsReactRedux from './page/news/NewsReactRedux.js';class App extends Component {  render() {    return (      
  • 登录
  • 主页
  • 关于我们
  • 新闻页面
); }}export default App;

十.退出登录处理

我们在/Home加一个按钮就是退出按钮他和我们的登录处理相反:

HomeReactRedux.js:

import { connect } from 'react-redux';//=====引入组件=====import Home from './Home.js'//=====react-redux 封装组件=====// 哪些 Redux 全局的 state 是我们组件想要通过 props 获取的?function mapStateToProps(state) {	return {}}// 哪些 action 创建函数是我们想要通过 props 获取的?function mapDispatchToProps(dispatch) {	return {		OUTLOGIN:function(history){			dispatch({type:"OUT_LOGIN"})			history.push("/")					}	};}//封装传递state和dispatchvar HomeReactRedux = connect(mapStateToProps,mapDispatchToProps)(Home);export default HomeReactRedux

Home.js:

import React, { Component } from 'react';//=====组件=====class Home extends Component {		render() {		return (			

主页

); } outLogin(){ this.props.OUTLOGIN(this.props.history); } componentDidMount() { console.log("Home渲染完毕") } }export default Home

十一.权限处理

1.显示级别

我们的网站在/地址是处在登录页面,这时候我们应该只有登录框,在进入主页之后会看到跳转链接,我们要获取我们的登录状态,还控制一些标签的显示:

152615_W8jl_2352644.png

我们在App.js存放了我们的导航,我们只需要对这个组件利用react-redux做一次封装,拿到状态,利用style去处理即可:

我们把导航提出到组件,并且react-redux做封装,在App.js使用

Nav.js:

import React, { Component } from 'react';import {  Route,  Link} from 'react-router-dom';class Nav extends Component {  render() {    return (		
  • 登录
  • 主页
  • 关于我们
  • 新闻页面
); }}export default Nav;

NavReactRedux.js:

import { connect } from 'react-redux';//=====引入组件=====import Nav from './Nav.js'//=====react-redux 封装组件=====// 哪些 Redux 全局的 state 是我们组件想要通过 props 获取的?function mapStateToProps(state) {	return {		isLogin:state.isLogin	}}// 哪些 action 创建函数是我们想要通过 props 获取的?function mapDispatchToProps(dispatch) {	return {};}//封装传递state和dispatchvar NavReactRedux = connect(mapStateToProps,mapDispatchToProps)(Nav);export default NavReactRedux

App.js我们使用封装后导航:

import React, { Component } from 'react';import {  Route,  Link} from 'react-router-dom';import NavReactRedux from './NavReactRedux.js';import LoginReactRedux from './page/login/LoginReactRedux.js';import HomeReactRedux from './page/home/HomeReactRedux.js';import About from './page/about/About.js';import NewsReactRedux from './page/news/NewsReactRedux.js';class App extends Component {  render() {    return (      
); }}export default App;

 

我们测试是没有问题的,我们在显示一级的权限做的差不多了!

 

2.逻辑级别

如果用户直接输入地址怎么办?所以我们在路由对应的页面都要加入登录状态的判断,然后处理是留在当前页面还是跳到登录页面:

我们登录后的页面只有三个,我们先对Home做一个处理,其他的类似:

HomeReactRedux.js:

import { connect } from 'react-redux';//=====引入组件=====import Home from './Home.js'//=====react-redux 封装组件=====// 哪些 Redux 全局的 state 是我们组件想要通过 props 获取的?function mapStateToProps(state) {	return {		isLogin:state.isLogin	}}// 哪些 action 创建函数是我们想要通过 props 获取的?function mapDispatchToProps(dispatch) {	return {		OUTLOGIN:function(history){			dispatch({type:"OUT_LOGIN"})			history.push("/")					}	};}//封装传递state和dispatchvar HomeReactRedux = connect(mapStateToProps,mapDispatchToProps)(Home);export default HomeReactRedux

Home.js

import React, { Component } from 'react';import {Redirect} from 'react-router-dom';//=====组件=====class Home extends Component {		render() {		if(this.props.isLogin==false){			return 
} return (

主页

); } outLogin(){ this.props.OUTLOGIN(this.props.history); } componentDidMount() { console.log("Home渲染完毕") } }export default Home

其他路由页面同理!!!

十二.刷新问题

我们本地存储可以使用cookie还可以使用localstorage,我们刷新应用就获取localstorage对登录状态的设置,然后action即可!

不过不管是cookie还是localstorage如果用户浏览器的安全级别高就完蛋了,我们存放在这个2个里面哪一个都会遇到这个问题。

我们或许可以这样做,在刷新我们就向后台发送一个请求,这个请求会返回用户是否在登录中和返回用户的一些信息,根据状态我们用手动方法跳转链接。

十三.404

这个其实使用的就是router为我们提供的 Switch 组件:

import React, { Component } from 'react';import {  Route,  Link,  Switch} from 'react-router-dom';import NavReactRedux from './NavReactRedux.js';import LoginReactRedux from './page/login/LoginReactRedux.js';import HomeReactRedux from './page/home/HomeReactRedux.js';import About from './page/about/About.js';import NewsReactRedux from './page/news/NewsReactRedux.js';import NotFind from './page/notFind/NotFind.js';class App extends Component {  render() {    return (      
); }}export default App;

十四.打包

我们执行下面命令:

npm run build

171411_ByzU_2352644.png

打包后文件index.html删除 /

171520_Wycq_2352644.png

我们打开index.html会出现问题,提示404,我们可以把路由处理改为:

171336_kw8V_2352644.png

HashRouter方式

index.js:

import React from 'react';import ReactDOM from 'react-dom';import {HashRouter as Router} from 'react-router-dom';//redux 和react-redux(关联react和redux)import { createStore } from 'redux';import { Provider } from 'react-redux';//reducers 状态树state和逻辑操作import rootRedux from './rootRedux.js'import App from './App.js';import registerServiceWorker from './registerServiceWorker';//创建状态树和设置//生成状态树对象const store = createStore(rootRedux);//start 状态树应用到全局 通过ProviderReactDOM.render(
, document.getElementById('root'));registerServiceWorker();

(打包后文件index.html删除 /)

 

完整的demo代码:

 

转载于:https://my.oschina.net/tbd/blog/1551481

你可能感兴趣的文章
c++ abs与fabs
查看>>
JVM 运行时数据区域
查看>>
数据库扩展
查看>>
WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu
查看>>
Eclipse 调试 Java 程序的技巧
查看>>
Project Euler 95:Amicable chains 亲和数链
查看>>
HTML5调用传感器的资料汇总
查看>>
maven安装配置
查看>>
全民Scheme(0):lat的定义
查看>>
[转]Worksheet.Change Event (Excel)
查看>>
cpu性能探究 :cache line 原理
查看>>
mysql忘记root密码拯救方法(flush privileges)
查看>>
[转载]UML用例图总结
查看>>
LinkedBlockingQueue
查看>>
Lucene.Net+盘古分词器(详细介绍)(转)
查看>>
HDU 4902 Nice boat(线段树)
查看>>
正确理解Python文件读写模式字w+、a+和r+
查看>>
不可不知的DIP、IoC、DI以及IoC容器
查看>>
大漠教程 找字 找图片
查看>>
不同时间复杂度的规模上限
查看>>