本文将介绍reactjs–无法确定如何在同一组件上使用Redux和React-router的详细情况,特别是关于react不在同一个项目下怎么跳转的相关信息。我们将通过案例分析、数据研究等多种方式,帮
本文将介绍reactjs – 无法确定如何在同一组件上使用Redux和React-router的详细情况,特别是关于react 不在同一个项目下怎么跳转的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?、react+react-router+react-redux+nodejs+mongodb项目、react+react-router+redux+react-redux构建一个简单应用、reactjs – (Universal React redux react-router)如何避免在初始浏览器加载时重新获取路由数据?的知识。
本文目录一览:- reactjs – 无法确定如何在同一组件上使用Redux和React-router(react 不在同一个项目下怎么跳转)
- ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?
- react+react-router+react-redux+nodejs+mongodb项目
- react+react-router+redux+react-redux构建一个简单应用
- reactjs – (Universal React redux react-router)如何避免在初始浏览器加载时重新获取路由数据?
reactjs – 无法确定如何在同一组件上使用Redux和React-router(react 不在同一个项目下怎么跳转)
我收到了这个错误:
Type 'ComponentClass<{}>' is not assignable to type 'StatelessComponent<void | RouteComponentProps<any>> | ComponentClass<void | RouteComponentProps<a...'. Type 'ComponentClass<{}>' is not assignable to type 'ComponentClass<void | RouteComponentProps<any>>'. Type '{}' is not assignable to type 'void | RouteComponentProps<any>'. Type '{}' is not assignable to type 'RouteComponentProps<any>'.
这是我的App组件:
interface AppProps extends React.Props<void> { todos: TodoItemData[]; actions: typeof TodoActions; }; interface AppState { /* empty */ } class App extends React.Component<AppProps,AppState>{ render() {return (<div></div>); } } function mapStatetoProps(state: RootState) { return { todos: state.todos }; } function mapdispatchToProps(dispatch) { return { actions: bindActionCreators(TodoActions as any,dispatch) }; } export default connect( mapStatetoProps,mapdispatchToProps )(App);
如果我通过void或React.Props更改我的App组件AppProps的声明我没有错误,但我总是有一个AppProps.
我不会理解为什么它不起作用,AppProps正在从React.Props扩展.你看错了吗?
我通过使用RouteComponentProps接口扩展我的AppProps接口来修复它,因此在您的情况下,AppProps接口将如下所示:
import { RouteComponentProps } from 'react-router'; ... interface AppProps extends RouteComponentProps<any> { todos: TodoItemData[]; actions: typeof TodoActions; }
ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?
我曾尝试将redux与react-native-router-flux提供的路由结合使用.
简单来说,它不起作用:
> redux状态修改不会出现在视图中,但可以成功记录到控制台
>每次执行操作时,将重新创建包含场景的整个组件树,这会在控制台中产生大量警告,即已创建具有键“xyz”的场景.
我做了什么:
我使用了react-native-router-flux的官方示例应用程序,并添加了一个基于redux的简单反例:
>一个简单的状态:“counter”(可能是一个整数)
>减速器和动作(增量,减量)
下面我将展示一些代码,但也会在github上找到我的example application,请随时查看:https://github.com/itinance/react-native-router-flux.“示例”目录是原始示例应用程序.而“ExampleRedux”是带有redux堆栈和示例reducers(计数器)的示例的副本,我在这里谈论的是什么.
提供者和商店的主要应用程序组件:
import * as reducers from './components/reducers'; const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); const reducer = combineReducers(reducers); const store = createStoreWithMiddleware(reducer); export default class Example extends React.Component { render() { return ( <Provider store={store}> <ExampleContainer/> </Provider> ); } }
我的减速器:
const initialState = { count: 0 }; export default function counter(state = initialState,action = {}) { switch (action.type) { case "INCREMENT": console.log("do increment",state,{ ...state,count: state.count + 1 } ); return { ...state,count: state.count + 1 }; case "DECREMENT": return { ...state,count: state.count - 1 }; default: return state; } }
redux’“connect”的内部应用程序容器:
我将状态和动作传递给场景组件:
<Scene key="launch" component={Launch} title="Launch" initial={true} state={state} {...actions} />
这个ExampleContainer的整个代码:
class ExampleContainer extends React.Component { constructor(props) { super(props); } render() { const { state,actions } = this.props; console.log("Props",this.props,actions); // everything ok here return <Router createReducer={reducerCreate}> <Scene key="modal" component={Modal} > <Scene key="root" hideNavBar={true}> <Scene key="echo" clone component={EchoView} /> <Scene key="register" component={Register} title="Register"/> <Scene key="home" component={Home} title="Replace" type="replace"/> <Scene key="launch" component={Launch} title="Launch" initial={true} state={state} {...actions} /> .... lots of other scenes ... </Scene> </Scene> <Scene key="error" component={Error}/> </Scene> </Router>; } } export default connect(state => ({ state: state.counter }),(dispatch) => ({ actions: bindActionCreators(actions,dispatch) }) )(ExampleContainer);
这是具有简单计数器功能的死亡简易LaunchScreen(以及用于演示路由的示例路由):
class Launch extends React.Component { constructor(props) { super(props); console.log(props); } render(){ const { state,increment,decrement } = this.props; console.log("Props 2: ",decrement); return ( <View {...this.props} style={styles.container}> <Text>Launch page</Text> <Text>{state.count}</Text> <Button onPress={increment}>Increment</Button> <Button onPress={()=>Actions.login({data:"Custom data",title:"Custom title" })}>Go to Login page</Button> <Button onPress={Actions.register}>Go to Register page</Button> <Button onPress={Actions.register2}>Go to Register page without animation</Button> <Button onPress={()=>Actions.error("Error message")}>Popup error</Button> <Button onPress={Actions.tabbar}>Go to TabBar page</Button> <Button onPress={Actions.pop}>back</Button> </View> ); } }
单击Increment-Button时,可以完美地调度操作.在控制台中,可以成功记录新状态.每次点击都会逐一递增.但不是在视图中.
当我省略路由器和场景并仅将启动屏幕激活为单个组件时,一切正常.
题:
如何使这个redux应用程序工作,视图将正确更新其状态?
为了完整起见,整个代码可以在github找到.
解决方法
export default connect(state => ({ state: state.counter }),dispatch) }) )(Launch);
然后正确的值将显示在您的日志中
react+react-router+react-redux+nodejs+mongodb项目
一个实际项目(OA系统)中的部分功能。这个demo中引入了数据库,数据库使用了mongodb。安装mongodb才能运行完整的功能。要看完整的项目可以移步我的github
技术栈
- React v15.6.2
- react-redux
- redux
- react-router-dom
- webpack
- nodeJs
- mongodb
- axios
项目结构
```
.
├─ exampleImg/ # 截图
├─ note/ # 学习笔记
├─ my-app/ # 源码目录(开发都在这里进行)
│ ├─ config/ # 服务配置文件
| |── controller # 处理网络请求
│ ├─ model/ # mongoose Model
│ ├─ route/ # nodeJs 路由配置
│ ├── schema/ # mongoose Schema
│ ├── scripts/ # 启动服务的文件
│ ├── src/ # react代码从这里开始
│ │ ├─ components/ # 全局组件
│ │ ├─ css/ # 全局css样式
| | |── global/ # 全局方法
| | |── pages/ # 页面
| | | |── att/ # 考勤分组模块
| | | |── attendance/ # 通讯录模块
| | | |── department/ # 部门管理模块
| | | |── holiday/ # 假期管理
| | | |── member/ # 员工管理
| | |── router/ # router
| | |── store/ # redux
| | |── App.css
| | |── App.js
| | |── index.css
| | |── index.js # 入口
```
项目截图
1.通讯录
2.假期管理
3.考勤分组
4.选择人员
5.员工管理
6.部门管理
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
reactjs – (Universal React redux react-router)如何避免在初始浏览器加载时重新获取路由数据?
const mapStatetoProps = (state) => ({ posts: state.posts }) @connect(mapStatetoProps) class Blog extends Component { static fetchData (dispatch) { return dispatch(fetchPosts()) } render () { return ( <PostsList posts={this.props.posts} /> ) } }
…并在服务器端的初始渲染之前收集所有承诺…
match({ routes,location },(error,redirectLocation,renderProps) => { const promises = renderProps.components .filter((component) => component.fetchData) .map((component) => component.fetchData(store.dispatch)) Promise.all(promises).then(() => { res.status(200).send(renderView()) }) })
它工作正常,服务器等待,直到我的所有承诺在渲染应用程序之前得到解决.
现在,在我的客户端脚本上,我正在做与服务器上类似的事情……
... function resolveRoute (props) { props.components .filter((component) => component.fetchData) .map((component) => component.fetchData(store.dispatch)) return <RouterContext {...props} /> } render(( <Provider store={store}> <Router history={browserHistory} routes={routes} render={resolveRoute} /> </Provider> ),document.querySelector('#app'))
它工作正常.但是,正如你可以推断的那样,在初始页面渲染中,静态fetchData被调用两次(一次在服务器上,一次在客户端上),我不希望这样.
关于如何解决这个问题有什么建议吗?建议?
对于我的项目,我正在做与你类似的事情;我有一个静态的fetchData方法,我循环遍历renderProps中的组件,然后我调用静态方法并等待promises解析.
然后,我从我的redux商店调用get状态,对其进行字符串化,并将其传递给服务器上的渲染函数,以便它可以在客户端上渲染出初始状态对象.
从客户端,我只需抓住该初始状态变量并将其传递给我的redux商店.然后,Redux将处理使您的客户端存储与服务器上的存储匹配.从那里,您只需将您的商店转移到提供商,然后照常继续.您根本不需要在客户端上调用静态方法.
举一个我所说的例子,你可以查看我的github项目代码解释自己. https://github.com/mr-antivirus/riur
希望有所帮助!
[编辑]这是代码!
Client.js
'use strict' import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import { Router,browserHistory } from 'react-router'; import createStore from '../shared/store/createStore'; import routes from '../shared/routes'; const store = createStore(window.__app_data); const history = browserHistory; render ( <Provider store={store}> <Router history={history} routes={routes} /> </Provider>,document.getElementById('content') )
Server.js
app.use((req,res,next) => { match({ routes,location:req.url },(err,renderProps) => { if (err) { return res.status(500).send(err); } if (redirectLocation) { return res.redirect(302,redirectLocation.pathname + redirectLocation.search); } if (!renderProps) { return next(); } // Create the redux store. const store = createStore(); // Retrieve the promises from React Router components that have a fetchData method. // We use this data to populate our store for server side rendering. const fetchedData = renderProps.components .filter(component => component.fetchData) .map(component => component.fetchData(store,renderProps.params)); // Wait until ALL promises are successful before rendering. Promise.all(fetchedData) .then(() => { const asset = { javascript: { main: '/js/bundle.js' } }; const appContent = renderToString( <Provider store={store}> <RouterContext {...renderProps} /> </Provider> ) const isProd = process.env.NODE_ENV !== 'production' ? false : true; res.send('<!doctype html>' + renderToStaticmarkup(<Html assets={asset} content={appContent} store={store} isProd={isProd} />)); }) .catch((err) => { // Todo: Perform better error logging. console.log(err); }); }); });
RedditContainer.js
class Reddit extends Component { // Used by the server,ONLY,to fetch data static fetchData(store) { const { selectedSubreddit } = store.getState(); return store.dispatch(fetchPosts(selectedSubreddit)); } // This will be called once on the client componentDidMount() { const { dispatch,selectedSubreddit } = this.props; dispatch(fetchPostsIfNeeded(selectedSubreddit)); } ... Other methods };
HTML.js
'use strict'; import React,{ Component,PropTypes } from 'react'; import ReactDom from 'react-dom'; import Helmet from 'react-helmet'; import serialize from 'serialize-javascript'; export default class Layout extends Component { static propTypes = { assets: PropTypes.object,content: PropTypes.string,store: PropTypes.object,isProd: PropTypes.bool } render () { const { assets,content,store,isProd } = this.props; const head = Helmet.rewind(); const attrs = head.htmlAttributes.toComponent(); return ( <html {...attrs}> <head> {head.base.toComponent()} {head.title.toComponent()} {head.Meta.toComponent()} {head.link.toComponent()} {head.script.toComponent()} <link rel='shortcut icon' href='/favicon.ico' /> <Meta name='viewport' content='width=device-width,initial-scale=1' /> </head> <body> <div id='content' dangerouslySetInnerHTML={{__html: content}} /> <script dangerouslySetInnerHTML={{__html: `window.__app_data=${serialize(store.getState())}; window.__isProduction=${isProd}`}} charSet='utf-8' /> <script src={assets.javascript.main} charSet='utf-8' /> </body> </html> ); } };
重申……
>在客户端上,获取状态变量并将其传递给您的商店.>在服务器上,遍历组件,调用fetchData并传递商店.等待承诺得到解决,然后渲染.>在HTML.js(您的renderView函数)中,序列化您的Redux存储并将输出呈现为客户端的javascript变量.>在React组件中,仅为要调用的服务器创建静态fetchData方法.发送您需要的操作.
今天关于reactjs – 无法确定如何在同一组件上使用Redux和React-router和react 不在同一个项目下怎么跳转的分享就到这里,希望大家有所收获,若想了解更多关于ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?、react+react-router+react-redux+nodejs+mongodb项目、react+react-router+redux+react-redux构建一个简单应用、reactjs – (Universal React redux react-router)如何避免在初始浏览器加载时重新获取路由数据?等相关知识,可以在本站进行查询。
本文标签: