GVKun编程网logo

reactjs – 无法确定如何在同一组件上使用Redux和React-router(react 不在同一个项目下怎么跳转)

14

本文将介绍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 不在同一个项目下怎么跳转)

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扩展.你看错了吗?

我遇到了与react-router@4.1.1类似的问题.

我通过使用RouteComponentProps接口扩展我的AppProps接口来修复它,因此在您的情况下,AppProps接口将如下所示:

import { RouteComponentProps } from 'react-router';
...

interface AppProps extends RouteComponentProps<any> {
  todos: TodoItemData[];
  actions: typeof TodoActions;
}

ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?

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找到.

解决方法

您可能忘记将Launch组件连接到商店.你想要做的是类似于你在ExampleContainer中所做的,即
export default connect(state => ({
   state: state.counter
 }),dispatch)
 })
)(Launch);

然后正确的值将显示在您的日志中

react+react-router+react-redux+nodejs+mongodb项目

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构建一个简单应用

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)如何避免在初始浏览器加载时重新获取路由数据?

reactjs – (Universal React redux react-router)如何避免在初始浏览器加载时重新获取路由数据?

我在Route组件上使用静态fetchData方法…
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-routerreact 不在同一个项目下怎么跳转的分享就到这里,希望大家有所收获,若想了解更多关于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)如何避免在初始浏览器加载时重新获取路由数据?等相关知识,可以在本站进行查询。

本文标签: