本篇文章给大家谈谈[译文&摘抄]在React&Redux中使用AJAX轮询,以及react-redux-router的知识点,同时本文还将给你拓展Flux、Redux到react-redux衍变发展之
本篇文章给大家谈谈[译文&摘抄]在 React & Redux 中使用 AJAX 轮询,以及react-redux-router的知识点,同时本文还将给你拓展Flux、Redux到react-redux衍变发展之Redux解读、react redux react-redux使用方式(一)、react 系列(五)在 React 中使用 Redux、react+react-router+redux+react-redux构建一个简单应用等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- [译文&摘抄]在 React & Redux 中使用 AJAX 轮询(react-redux-router)
- Flux、Redux到react-redux衍变发展之Redux解读
- react redux react-redux使用方式(一)
- react 系列(五)在 React 中使用 Redux
- react+react-router+redux+react-redux构建一个简单应用
[译文&摘抄]在 React & Redux 中使用 AJAX 轮询(react-redux-router)
原文地址:AJAX POLLING IN REACT WITH Redux
原文作者:Josh M
译文出自:掘金翻译计划
转自:https://juejin.im/post/5a43b6da5188257d167a7aef
译者:刘嘉一
校对者:yoyoyohamapi,FateZeros
目标:把一些有时序依赖的状态从服务端同步到客户端
方式:结合 React 组件的生命周期方法、 Redux 的 Action 以及 setTimeout 函数
HOW:
reducer 文件:
const initialState = { data: {},isFetching: false // 通过这个键值,判断是否正在获取数据 }; export function data (state = initialState,action) { switch (action.type) { case DATA_FETCH_BEGIN: { return { ...state,isFetching: true }; } case DATA_FETCH_SUCCESS: { return { isFetching: false,data: { ...state.data,action.payload }}; } case DATA_FETCH_ERROR: { return { ...state,isFetching: false }; } default: return state; }
Action 文件
export function dataFetch() { return { [CALL_API]: { types: [DATA_FETCH_BEGIN,DATA_FETCH_SUCCESS,DATA_FETCH_ERROR],endpoint: 'api/data/' } }; }
如何定义组件?
import React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import * as DataActions from 'actions/DataActions'; // 组件需要哪些 Redux 全局状态作为 props 传入? function mapStatetoProps(state) { return { data: state.data.data,isFetching: state.data.isFetching }; } // 组件需要哪些 Action 创建函数作为 props 传入? function mapdispatchToProps(dispatch) { return { dataActions: bindActionCreators(DataActions,dispatch) }; } @connect(mapStatetoProps,mapdispatchToProps) export default class AppContainer { componentwillReceiveProps(nextProps) { if (this.props.data !== nextProps.data) { clearTimeout(this.timeout); // 你可以在这里处理获取到的数据 if (!nextProps.isFetching) { this.startPoll(); } } } componentwillMount() { this.props.dataActions.dataFetch(); } componentwillUnmount() { clearTimeout(this.timeout); } startPoll() { this.timeout = setTimeout(() => this.props.dataActions.dataFetch(),15000); } }
Flux、Redux到react-redux衍变发展之Redux解读
续上篇,在Flux后,为了更好的实现MVC,Redux模式出现。
不同于 Flux ,Redux 不再有 dispatcher 的概念(Store已经集成了dispatch方法)。其次它依赖纯函数来替代事件处理器(即原来Flux中Dispatcher.register((action) 注册逻辑处理这块),这个纯函数叫做Reducer。另外使用到了一个新概念 context ,在React 组件间,数据是通过 props 属性由上向下(由父及子)进行传递的,当遇到多个层级多个组件间共享一个props,这种树形的由上而下的传参方式就显得过于繁琐,context 便很巧妙的解决了这个问题,参数只需从树顶点设置一次,便可在其所有枝节点都能共享到。
看了react-redux官方源码,总结出其redux思想主要由四个部分组成:reducers、store(redux)、react-redux和view。大致画了个图,其逻辑关系如下:
为了让大家更好理解Redux思想,以设定/更改全局主题颜色为例,本demo暂不会引用官方已封装好的 ''redux''和''react-redux'' 模块,而是抽离出核心代码综合编写了一个demo。(建议先执行一遍demo,按着代码理解这些概念,会轻松很多)
源码地址:https://github.com/smallH/redux-demo.git
reducers
reducers,入参为:组件当前所在状态state,将要处理的动作 action。action通常是一个对象,由类型和值{type, value}组成,通过switch(action.type)来筛选类型。简单来说,reducers就是组件状态发生变化时主要逻辑处理的地方。其代码如下:
// reducers.js
const themeReducer = (state, action) => {
if (!state) return {
themeColor: ''red''
}
// 处理各类action,并返回最新的状态
switch (action.type) {
case ''CHANGE_COLOR'':
return { ...state, themeColor: action.themeColor }
default:
return state
}
}
export default themeReducer
上面代码表示,当 action 类型为''CHANGE_COLOR''时(我告诉你我要改变颜色啦),则改变颜色状态值 state.themeColor 为action.themeColor。其中{ ...state, themeColor: action.themeColor }是一种语法糖写法,表示返回一个新对象 newState ,它不仅继承了原有入参 state的数据结构和值,还顺道修改了themeColor属性值。注意哦,这种写法的好处就是实现了返回的新状态值newState 和 state 在内存中没有指向同一引用,是两个各自不想关的对象,也可以理解为深度拷贝吧。
store(redux)
核心其实就是就是官方模块中的引用的redux:
import { createStore } from ''redux''
但在本demo中我们并不直接引用,我们先来看看代码:
// redux.js
export const createStore = (reducer) => {
let state = null
const listeners = []; // 事件监听列表
const subscribe = (listener) => listeners.push(listener); // 定义添加事件对外接口
const getState = () => state; // 定义获取状态总值对外接口
// 定义驱动 Aciton 的对外接口,每次驱动会遍历执行listeners列表里的所有事件
const dispatch = (action) => {
state = reducer(state, action)
listeners.forEach((listener) => listener())
}
dispatch({}); // 首次初始化state
return {
getState,
dispatch,
subscribe
}
}
该模块以reducer为入参,返回了三个带有核心功能的对象{getState, dispatch, subscribe},目的是对外提供了状态获取和更新的渠道。
getState:获取所有通过store管理的组件的状态值。
dispatch:驱动reducer执行状态更新,并遍历事件监听列表,使在状态更新后自动刷新(渲染)dom节点。
subscribe:添加需要自动刷新的dom节点的_updateProps()函数到监听列表。
react-redux
该模块比较复杂,它提供了两个高阶组件Provider和 connect 函数。在看本模块前如果不了解高阶函数的意义和context功能,可以先看一下:react系列(21)高阶组件 和 react系列(17)跨组件树传递数据 context
高阶组件Provider:很简单,主要功能是提供 context 的全局状态入参 store 设置。
// 高阶组件 Provider
export class Provider extends React.Component {
static propTypes = {
store: PropTypes.object,
children: PropTypes.any
}
static childContextTypes = {
store: PropTypes.object
}
// 通过对context调用设置store
getChildContext() {
return {
store: this.props.store
}
}
render() {
return(
<div>{this.props.children}</div>
)
}
}
高阶组件connect:主要功能是为了连接起视图层view和store。
import React from ''react''
import PropTypes from ''prop-types''
// 高阶组件 contect
export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
class Connect extends React.Component {
// 通过对context调用获取store
static contextTypes = {
store: PropTypes.object
}
constructor() {
super()
this.state = {
allProps: {}
}
}
// 第一遍需初始化所有组件初始状态
componentWillMount() {
const store = this.context.store
this._updateProps()
store.subscribe(() => this._updateProps()); // 加入_updateProps()至store里的监听事件列表
}
// 执行action后更新props,使组件可以更新至最新状态(类似于setState)
_updateProps() {
const store = this.context.store;
let stateProps = mapStateToProps ?
mapStateToProps(store.getState(), this.props) : {} // 防止 mapStateToProps 没有传入
let dispatchProps = mapDispatchToProps ?
mapDispatchToProps(store.dispatch, this.props) : {} // 防止 mapDispatchToProps 没有传入
this.setState({
allProps: {
...stateProps,
...dispatchProps,
...this.props
}
})
}
render() {
return <WrappedComponent {...this.state.allProps} />
}
}
return Connect
}
高阶组件connect有三个入参:mapStateToProps, mapDispatchToProps 和 WrappedComponent。
首先需要明白,react-redux模块的一个主要目的就是可以把view和store连接起来,store存储了所有组件的状态值state和事件处理方法action,但并不代表所有的组件都需要用到全部的state和action,于组件而言,最好的办法是我告诉store我需要那些 state和action 你给我就好,mapStateToProps和mapDispatchToProps就是干这个事情的。
mapStateToProps:告诉store ,本组件渲染时所需的props值。
mapDispatchToProps :告诉store,本组件触发事件时所需的action。
WrappedComponent:将要被包装升级的原组件,最好为Dumb组件。Dumb组件是指只可以也仅可以通过props来控制组件渲染内容,它也是最符合react设计思想的组件设计,复用性高耦合性低。
现在,回过头来看看最开始的逻辑图,是不是清楚了很多。
view
即将要被渲染的组件。
import React from ''react''
import PropTypes from ''prop-types''
import { connect } from ''../react-redux''
class ThemeSwitch extends React.Component {
// 设置所需参数
static propTypes = {
themeColor: PropTypes.string,
onSwitchColor: PropTypes.func
}
handleSwitchColor(color) {
if(this.props.onSwitchColor) {
this.props.onSwitchColor(color)
}
}
render() {
return(
<div>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, ''red'')}>Style-Red</button>
<button
style={{ color: this.props.themeColor }}
onClick={this.handleSwitchColor.bind(this, ''blue'')}>Style-Blue</button>
</div>
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
themeColor: state.themeColor
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onSwitchColor: (color) => {
dispatch({
type: ''CHANGE_COLOR'',
themeColor: color
})
}
}
}
ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch)
export default ThemeSwitch
结合上面的react-redux模块高阶组件的意图,看起来就很明白了,没什么好讲述的了,有问题可以留言。
最终demo运行效果:点击按钮Style-Red主题颜色变为红色,点击按钮Style-Red主题颜色变为蓝色。
最后,我们试着把上面例子中的 redux.js 和 react-redux.js 文件删除,改为直接引用官方的 ''redux'' 和 ''react-redux'':
// 安装
$ npm install redux -S
$ npm install react-redux -S
// 引用
import { createStore } from ''redux''
import { Provider } from ''react-redux''
会发现程序依然运行起来了,而且结果是一样的,棒棒的!这就是Redux模式了,而官方提供的 ''redux'' 和 ''react-redux'' 模块,只过不是对上面代码的封装和多了一些辅助插件而已,下一篇将介绍这些插件的用法。
react redux react-redux使用方式(一)
在react的项目中使用redux的基本用法
文件主要分四部分
- type
- reducer
- action
- 入口index
type文件
项目中不是必须有这个文件的存在,只是为了在大型项目中利于维护将各种type独立出来。
/** 文件示例*/
export const USER_NAME = ''USER_NAME'';
export const USER_CODE = ''USER_CODE'';
reducer文件
reducer是一个函数,接收action和当前state作为参数,配合action中的type对state的值进行更新
/** 文件示例*/
import { USER_NAME, USER_CODE } from ''../type/module1'';
const userInfo = {
userName: ''马云'',
userCode: ''my'',
};
export function USER_INFO(state = userInfo, action) {
switch (action.type) {
case USER_NAME:
return Object.assign({}, state, { userName: action.name });
case USER_CODE:
return Object.assign({}, state, { userCode: action.code });
default:
return state;
}
}
action文件
action是改变state的唯一办法,action是一个对象其中type是必须的,其它参数可以自由设置(多数情况下这些参数就是更新state所需要的值)
/** 文件示例*/
export const USER_CODE_ACTION = (code) => {
return {
type: ''USER_CODE'',
code,
}
};
export const USER_NAME_ACTION = (name) => {
return {
type: ''USER_NAME'',
name,
}
};
入口文件
入口文件中重点是combineReducers这个辅助函数,他可以将多个reducer合并成最终的reducer,后续使用时可以对这个reducer调用createStore
/** 文件示例*/
import { combineReducers } from ''redux'';
import reducer from ''./reducer'';
const store = combineReducers({
...reducer
});
export default store;
下面是在组件中如何使用
在根组件中创建store
import state from ''./redux'';
import { Provider } from ''react-redux'';
import { createStore } from ''redux'';
const store = createStore(state);
function App() {
return (
<Provider store={store}>
<div className="App">
<ComOne/>
<ComTwo/>
</div>
</Provider>
);
}
在组件中如何使用
import { connect } from ''react-redux'';
// 引入action
import { USER_CODE_ACTION } from ''../../redux/action/module1'';
function ComOne(props) {
const [ count, setCount ] = useState(0);
return (
<div className="ComOne">
<div>{props.userCode}</div>
<Button type=''primary'' onClick={ ()=>{props.USER_CODE_ACTION(Math.random())}}>提交</Button>
</div>
);
}
// mapStateToProps方法:将state中的变量合成到组件的props中
const mapStateToProps = (state) => {
return {
userCode: state.USER_INFO.userCode
}
};
// mapDispatchToProps方法:将action合成到组件的props中,在组件中可以直接props.USER_CODE_ACTION()进行调用
const mapDispatchToProps = {
USER_CODE_ACTION
};
/**
* connect api
* 首先connect之所以会成功,是因为Provider组件, 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件,它真正连接 Redux 和 React
*/
export default connect(mapStateToProps, mapDispatchToProps)(ComOne);
react 系列(五)在 React 中使用 Redux
上一篇展示了 Redux 的基本使用,可以看到 Redux 非常简单易用,不限于 React,也可以在 Angular、Vue 等框架中使用,只要需要 Redux 的设计思想的地方,就可以使用它。
这篇主要讲解在 React 中使用 Redux,首先是安装。
安装 React Redux
yarn add redux
yarn add react-redux
有两个概念:
1. 容器组件(Container Components)
2. 展示组件(Presentational Components)
展示组件
- 更关注数据展示,所以会写一些 DOM 嵌套和 CSS
- 通常不依赖 Redux,直接从 props 中获取数据
- 通常没有 state,偶尔会用 state 来保存一些展示状态,如 class 等
- 交互也通过 props 回调发起,不直接发起 action
容器组件
- 通常作为数据源,做数据分发工作
- 依赖 Redux
- 通过和 store 交互进行数据变更
- 通过 react-redux 生成
在我们的项目中,一般来说,会编写很多展示组件,少量的容器组件来包裹这些展示组件。
接下来写一个简单的计数器应用,先来划分容器组件和展示组件。
计数器有三个按钮,加、减、重置;一个展示区。
由于按钮既要触发 action,又要负责展示,所以需要做成混合组件。
先来编写展示组件,就是显示一下当前计数。
import React from ''react'';
const Counter = ({
count
}) => (
<p>当前计数为:<span style={{color: ''red''}}>count</span></p>
)
export default Counter;
一般来说,容器组件就是通过 store.subscribe 传入回调,订阅 store 的变化,再去把值通过 props 传入各个组件中。
在 react-redux 中实现了 connect 方法,它生成一个高阶组件,就是前面提到的容器组件。这个方法做了性能优化避免不必要的重复渲染,建议使用该方法。
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
mapStateToProps 是一个 Function,用来监听 Redux Store 的变化,将 store 的值,映射为对应的 props 属性。
const mapStateToProps = ({count}) => {count};
// 或者
const mapStateToProps2 = (state) => {
count: state.count
}
接下来生成一个容器组件。
import { connect } from ''react-redux'';
const ConnectCounter = connect(
mapStateToProps
)(Counter);
export default ConnectCounter;
接下来是按钮组件,按钮组件既需要展示,又有数据交互,做成混合组件。
由于,需要 dispatch,所以需要给 connect 传入第二个参数。
mapDispatchToProps 可以是 Object 或者 Function。用来将 dispatch 映射到 props 上。
const mapDispatchToProps = dispatch => {
return {
plus: () => dispatch({
type: ''PLUS''
})
}
}
// 或者结合上篇提到的bindActionCreators合成一个对象
function plus() {
return {
type: "PLUS"
};
}
function minus() {
return {
type: "MINUS"
};
}
const mapDispatchToProps2 = dispatch => {
return bindActionCreators({ plus, minus }, dispatch)
}
import React from ''react'';
let Button = ({plus, minus}) => {
return (
<>
<button onClick={plus}>{''plus''}</button>
<button onClick={minus}>{''minus''}</button>
</>
)
};
Button = connect(()=>{}, mapDispatchToProps2)(Button);
export default Button;
最后,提供一个 Provider 用来提供全局 store。完整例子在这里 - codesandbox。 感谢阅读。
react+react-router+redux+react-redux构建一个简单应用
完整的demo代码:
https://gitee.com/dgx/demo-react
演示:
http://dgx.gitee.io/demo-react/build/index.html#/
一.基本知识
我们已经学习了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
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
index.js
import React from ''react'';
import ReactDOM from ''react-dom'';
import App from ''./App'';
import registerServiceWorker from ''./registerServiceWorker'';
ReactDOM.render(<App />, document.getElementById(''root''));
registerServiceWorker();
App.js
import React, { Component } from ''react'';
class App extends Component {
render() {
return (
<div className="App">
demo
</div>
);
}
}
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
等待完成...
我们的使用版本:
我们采用的react16.x和react-router4.x,不同的版本使用是有区别的,尤其路由使用上
五.创建目录结构和文件
page下存放我们路由使用的页面组件
六.创建路由页面和搭载路由
1.创建页面
这时候我们已经可以看到显示demo的页面,我们开始创建我们的页面:
login/Login.js
import React, { Component } from ''react'';
//=====组件=====
class Login extends Component {
render() {
return (
<div>
<h3>登录页面</h3>
<div>
用户名<input type="text" />
</div>
<div>
密码<input type="text" />
</div>
<div>
<button onClick={this.goLogin}>登录</button>
</div>
</div>
);
}
goLogin(){
alert("开始登录")
}
componentDidMount() {
console.log("Login渲染完毕")
}
}
export default Login
home/Home.js
import React, { Component } from ''react'';
//=====组件=====
class Home extends Component {
render() {
return (
<div>
<h3>主页</h3>
</div>
);
}
componentDidMount() {
console.log("Home渲染完毕")
}
}
export default Home
about/About.js
import React, { Component } from ''react'';
//=====组件=====
class About extends Component {
render() {
return (
<div>
<h3>关于我们</h3>
</div>
);
}
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 (
<div>
<h3>新闻页面</h3>
<ul>
{
this.state.list.map(function(item,i){
return <li key={item.id}>
<a>{item.title}</a>
<span>{item.con}</span>
</li>
})
}
</ul>
</div>
);
}
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(
<Router>
<App />
</Router>
, 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 (
<div className="App">
<ul>
<li>
<Link to="/">登录</Link>
</li>
<li>
<Link to="/Home">主页</Link>
</li>
<li>
<Link to="/About">关于我们</Link>
</li>
<li>
<Link to="/News">新闻页面</Link>
</li>
</ul>
<div>
<Route exact path="/" component={Login}/>
<Route exact path="/Home" component={Home}/>
<Route path="/About" component={About}/>
<Route path="/News" component={News}/>
</div>
</div>
);
}
}
export default App;
我们预览页面,就可以看到大概了:
七.redux和应用配合
创建我们的redux文件:
rootRedux.js(合并所有状态,对外接口):
import { combineReducers } from ''redux'';
//全局reducer
import isLogin from ''./indexRedux.js''
//子reducer
//合并reducer
var rootRedux = combineReducers({
isLogin
})
export default rootRedux
indexRedux.js(根状态树)我们存放登录状态,默认是未登录:
//reducer
var 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 状态树应用到全局 通过Provider
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
, document.getElementById(''root''));
registerServiceWorker();
我们为news创建reducer,把list放入在reducer中,
NewsRedux.js:
//reducer
var 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 (
<div>
<h3>新闻页面</h3>
<ul>
</ul>
</div>
);
}
componentDidMount() {
console.log("News渲染完毕")
}
}
export default News
rootRedux.js引入news的reducer:
import { combineReducers } from ''redux'';
//全局reducer
import isLogin from ''./indexRedux.js''
//子reducer
import NewsRedux from ''./page/news/NewsRedux.js''
//合并reducer
var rootRedux = combineReducers({
isLogin,
NewsRedux
})
export default rootRedux
八.利用react-redux链接react组件和redux
我们先以news的处理作为操作,首先用react-redux封装News.js组件:
创建NewsReactRedux.js:
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和dispatch
var 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 (
<div>
<h3>新闻页面</h3>
<ul>
{
this.props.list.map(function(item,i){
return <li key={item.id}>
<a>{item.title}</a>
<span>{item.con}</span>
</li>
})
}
</ul>
<button onClick={this.SORTREVERSE.bind(this)}>倒叙显示</button>
</div>
);
}
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 (
<div className="App">
<ul>
<li>
<Link to="/">登录</Link>
</li>
<li>
<Link to="/Home">主页</Link>
</li>
<li>
<Link to="/About">关于我们</Link>
</li>
<li>
<Link to="/News">新闻页面</Link>
</li>
</ul>
<div>
<Route exact path="/" component={Login}/>
<Route exact path="/Home" component={Home}/>
<Route path="/About" component={About}/>
<Route path="/News" component={NewsReactRedux}/>
</div>
</div>
);
}
}
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和dispatch
var LoginReactRedux = connect(mapStateToProps,mapDispatchToProps)(Login);
export default LoginReactRedux
login.js
import React, { Component } from ''react'';
//=====组件=====
class Login extends Component {
render() {
return (
<div>
<h3>登录页面</h3>
<div>
用户名<input type="text" ref="username" />
</div>
<div>
密码<input type="password" ref="password" />
</div>
<div>
<button onClick={this.goLogin.bind(this)}>登录</button>
</div>
</div>
);
}
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 (
<div className="App">
<ul>
<li>
<Link to="/">登录</Link>
</li>
<li>
<Link to="/Home">主页</Link>
</li>
<li>
<Link to="/About">关于我们</Link>
</li>
<li>
<Link to="/News">新闻页面</Link>
</li>
</ul>
<div>
<Route exact path="/" component={LoginReactRedux}/>
<Route exact path="/Home" component={Home}/>
<Route path="/About" component={About}/>
<Route path="/News" component={NewsReactRedux}/>
</div>
</div>
);
}
}
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和dispatch
var HomeReactRedux = connect(mapStateToProps,mapDispatchToProps)(Home);
export default HomeReactRedux
Home.js:
import React, { Component } from ''react'';
//=====组件=====
class Home extends Component {
render() {
return (
<div>
<h3>主页</h3>
<div>
<button onClick={this.outLogin.bind(this)}>退出登录</button>
</div>
</div>
);
}
outLogin(){
this.props.OUTLOGIN(this.props.history);
}
componentDidMount() {
console.log("Home渲染完毕")
}
}
export default Home
十一.权限处理
1.显示级别
我们的网站在/地址是处在登录页面,这时候我们应该只有登录框,在进入主页之后会看到跳转链接,我们要获取我们的登录状态,还控制一些标签的显示:
我们在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 (
<ul style={{display:this.props.isLogin?"block":"none"}}>
<li style={{display:this.props.isLogin?"none":"block"}}>
<Link to="/">登录</Link>
</li>
<li>
<Link to="/Home">主页</Link>
</li>
<li>
<Link to="/About">关于我们</Link>
</li>
<li>
<Link to="/News">新闻页面</Link>
</li>
</ul>
);
}
}
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和dispatch
var 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 (
<div className="App">
<NavReactRedux />
<div>
<Route exact path="/" component={LoginReactRedux}/>
<Route exact path="/Home" component={HomeReactRedux}/>
<Route exact path="/About" component={About}/>
<Route exact path="/News" component={NewsReactRedux}/>
</div>
</div>
);
}
}
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和dispatch
var 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 <Redirect to="/" />
}
return (
<div>
<h3>主页</h3>
<div>
<button onClick={this.outLogin.bind(this)}>退出登录</button>
</div>
</div>
);
}
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 (
<div className="App">
<NavReactRedux />
<div>
<Switch>
<Route exact path="/" component={LoginReactRedux}/>
<Route exact path="/Home" component={HomeReactRedux}/>
<Route exact path="/About" component={About}/>
<Route exact path="/News" component={NewsReactRedux}/>
<Route component={NotFind}/>
</Switch>
</div>
</div>
);
}
}
export default App;
十四.打包
我们执行下面命令:
npm run build
打包后文件index.html删除 /
我们打开index.html会出现问题,提示404,我们可以把路由处理改为:
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 状态树应用到全局 通过Provider
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
, document.getElementById(''root''));
registerServiceWorker();
(打包后文件index.html删除 /)
完整的demo代码:
https://gitee.com/dgx/demo-react
关于[译文&摘抄]在 React & Redux 中使用 AJAX 轮询和react-redux-router的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Flux、Redux到react-redux衍变发展之Redux解读、react redux react-redux使用方式(一)、react 系列(五)在 React 中使用 Redux、react+react-router+redux+react-redux构建一个简单应用的相关信息,请在本站寻找。
本文标签: