加速咱們的npm。css
npm install -g cnpm --registry=https://registry.npm.taobao.org
利用create-react-app 建立項目,執行下面建立咱們的demo-react應用:react
cd ......到你本身的路徑
create-react-app reactdemo
我習慣使用VSCode,我用vscode打開這個文件夾,目錄結構以下。git
咱們的項目須要:shell
react-router:npm
react-router-domjson
reduxredux
react-redux瀏覽器
在VSCode中打開powershell(Ctrl+`)安全
依次安裝cookie
cnpm install react-router --save cnpm install react-router-dom --save cnpm install redux --save cnpm install react-redux --save
打開package.json能夠看到咱們使用的版本:
不一樣的版本使用是有一些區別的,尤爲路由使用上
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
import React, { Component } from 'react'; //=====組件===== class Home extends Component { render() { return ( <div> <h3>主頁</h3> </div> ); } componentDidMount() { console.log("Home渲染完畢") } } export default Home
import React,{ Component } from 'react'; //=====組件===== class About extends Component { render() { return ( <div> <h3>關於咱們</h3> </div> ); } componentDidMount() { console.log("About渲染完畢") } } export default About
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
咱們把頁面建立完畢,修改index.js配置路由:
src/index.js:
1 import React from 'react'; 2 import ReactDOM from 'react-dom'; 3 import {BrowserRouter as Router} from 'react-router-dom'; 4 import './index.css'; 5 import App from './App'; 6 import * as serviceWorker from './serviceWorker'; 7 8 ReactDOM.render( 9 <Router> 10 <App /> 11 </Router> 12 , document.getElementById('root')); 13 14 // If you want your app to work offline and load faster, you can change 15 // unregister() to register() below. Note this comes with some pitfalls. 16 // Learn more about service workers: https://bit.ly/CRA-PWA 17 serviceWorker.unregister();
App.js完成咱們路由和頁面的使用:
import React from 'react'; import {Route, Link} from 'react-router-dom'; import './App.css'; import Login from './components/login/Login.js'; import Home from './components/home/Home.js'; import About from './components/about/About.js'; import News from './components/news/News.js'; function App() { 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;
咱們預覽頁面,就能夠看到大概了:
npm run start
src目錄下建立redux文件:
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
rootRedux.js(合併全部狀態,對外接口):
import { combineReducers } from 'redux'; //全局reducer import isLogin from './indexRedux.js' //子reducer //合併reducer var rootRedux = combineReducers({ isLogin }) export default rootRedux
index.js使用redux:
import React from 'react'; import ReactDOM from 'react-dom'; import {BrowserRouter as Router} from 'react-router-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; //redux import { createStore } from 'redux'; //react-redux(關聯react和redux) import { Provider } from 'react-redux'; //reducers 狀態樹state和邏輯操做 import rootRedux from './rootRedux.js' //建立狀態樹和設置 //生成狀態樹對象 const store = createStore(rootRedux); ReactDOM.render( <Provider store={store}> <Router> <App /> </Router> </Provider> , document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();
咱們爲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> { 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
rootRedux.js引入news的reducer:
import { combineReducers } from 'redux'; //全局reducer import isLogin from './indexRedux.js' //子reducer import NewsRedux from './components/news/NewsRedux.js' //合併reducer var rootRedux = combineReducers({ isLogin, NewsRedux, }) export default rootRedux
咱們先以news的處理做爲操做,首先用react-redux封裝News.js組件:
建立src/news/NewsReactRedux.js:.
import { connect } from 'react-redux'; //=====引入組件===== import News from './News.js' //=====react-redux 封裝組件===== // 哪些 Redux 全局的 state 是咱們組件想要經過 props 獲取的? //負責輸入邏輯,即將state映射到 UI 組件的參數(props) function mapStateToProps(state) { return { list: state.NewsRedux.list }; } // 哪些 action 建立函數是咱們想要經過 props 獲取的? //負責輸出邏輯,即將用戶對 UI 組件的操做映射成 Action。 function mapDispatchToProps(dispatch) { return { SORTREVERSE:function(){ dispatch({type:"SORT_REVERSE"}) } }; } //封裝傳遞state和dispatch //把redux的狀態數據和action所有發射給News組件 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 from 'react'; import {Route, Link} from 'react-router-dom'; import './App.css'; import Login from './components/login/Login.js'; import Home from './components/home/Home.js'; import About from './components/about/About.js'; import NewsReactRedux from './components/news/NewsReactRedux.js'; function App() { 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 from 'react'; import {Route, Link} from 'react-router-dom'; import './App.css'; import LoginReactRedux from './components/login/LoginReactRedux.js'; import Home from './components/home/Home.js'; import About from './components/about/About.js'; import NewsReactRedux from './components/news/NewsReactRedux.js'; function App() { 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
記得修改app.js
import React from 'react'; import {Route, Link} from 'react-router-dom'; import './App.css'; import LoginReactRedux from './components/login/LoginReactRedux.js'; import HomeReactRedux from './components/home/HomeReactRedux.js'; import About from './components/about/About.js'; import NewsReactRedux from './components/news/NewsReactRedux.js'; function App() { 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={HomeReactRedux}/> <Route path="/About" component={About}/> <Route path="/News" component={NewsReactRedux}/> </div> </div> ); } export default App;
咱們的網站在/地址是處在登陸頁面,這時候咱們應該只有登陸框,在進入主頁以後會看到跳轉連接,咱們要獲取咱們的登陸狀態,還控制一些標籤的顯示:
咱們在App.js存放了咱們的導航,咱們只須要對這個組件利用react-redux作一次封裝,拿到狀態,利用style去處理便可:
咱們把導航提出到組件,而且react-redux作封裝,在App.js使用
Navigation.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;
NavigationReactRedux.js
import { connect } from 'react-redux'; //=====引入組件===== import Navigation from './Navigation.js' //=====react-redux 封裝組件===== // 哪些 Redux 全局的 state 是咱們組件想要經過 props 獲取的? function mapStateToProps(state) { return { isLogin:state.isLogin } } // 哪些 action 建立函數是咱們想要經過 props 獲取的? function mapDispatchToProps(dispatch) { return {}; } //封裝傳遞state和dispatch var NavigationReactRedux = connect(mapStateToProps,mapDispatchToProps)(Navigation); export default NavigationReactRedux
App.js咱們使用封裝後導航:
import React from 'react'; import {Route, Link} from 'react-router-dom'; import './App.css'; import LoginReactRedux from './components/login/LoginReactRedux.js'; import HomeReactRedux from './components/home/HomeReactRedux.js'; import About from './components/about/About.js'; import NewsReactRedux from './components/news/NewsReactRedux.js'; import NavigationReactRedux from './components/navigation/NavigationReactRedux.js'; function App() { return ( <div className="App"> <NavigationReactRedux /> <div> <Route exact path="/" component={LoginReactRedux}/> <Route exact path="/Home" component={HomeReactRedux}/> <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 { 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
其餘路由頁面同理!!!其實也就是News頁面,目前咱們其它的頁面並不須要驗證
NewsReactRedux.js
import { connect } from 'react-redux'; //=====引入組件===== import News from './News.js' //=====react-redux 封裝組件===== // 哪些 Redux 全局的 state 是咱們組件想要經過 props 獲取的? //負責輸入邏輯,即將state映射到 UI 組件的參數(props) function mapStateToProps(state) { return { isLogin:state.isLogin, list: state.NewsRedux.list }; } // 哪些 action 建立函數是咱們想要經過 props 獲取的? //負責輸出邏輯,即將用戶對 UI 組件的操做映射成 Action。 function mapDispatchToProps(dispatch) { return { SORTREVERSE:function(){ dispatch({type:"SORT_REVERSE"}) } }; } //封裝傳遞state和dispatch //把redux的狀態數據和action所有發射給News組件 var NewsReactRedux = connect(mapStateToProps,mapDispatchToProps)(News); export default NewsReactRedux
News.js
import React,{ Component } from 'react'; import {Redirect} from 'react-router-dom'; //=====組件===== class News extends Component { constructor(props) { super(props); } render() { if(this.props.isLogin==false){ return <Redirect to="/" /> } 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
咱們本地存儲可使用cookie還可使用localstorage,咱們刷新應用就獲取localstorage對登陸狀態的設置,而後action便可!
不過無論是cookie仍是localstorage若是用戶瀏覽器的安全級別高就完蛋了,咱們存放在這個2個裏面哪個都會遇到這個問題。
咱們或許能夠這樣作,在刷新咱們就向後臺發送一個請求,這個請求會返回用戶是否在登陸中和返回用戶的一些信息,根據狀態咱們用手動方法跳轉連接。
先建立一個src/components/exception/NotFind.js文件app.js
import React, { Component } from 'react'; //=====組件===== class NotFind extends Component { render() { return ( <div> <h1>404錯誤</h1> <div> 找不到對應的網頁 </div> </div> ); } } export default NotFind
使用router爲咱們提供的 Switch 組件:
import React from 'react'; import {Route, Link,Switch} from 'react-router-dom'; import './App.css'; import LoginReactRedux from './components/login/LoginReactRedux.js'; import HomeReactRedux from './components/home/HomeReactRedux.js'; import About from './components/about/About.js'; import NewsReactRedux from './components/news/NewsReactRedux.js'; import NavigationReactRedux from './components/navigation/NavigationReactRedux.js'; import NotFind from './components/exception/NotFind.js'; function App() { return ( <div className="App"> <NavigationReactRedux /> <div> <Switch> <Route exact path="/" component={LoginReactRedux}/> <Route exact path="/Home" component={HomeReactRedux}/> <Route path="/About" component={About}/> <Route path="/News" component={NewsReactRedux}/> <Route component={NotFind}/> </Switch> </div> </div> ); } export default App;
咱們執行下面命令:
npm run build
在使用BrowserRouter發佈的時候會遇到刷新404錯誤問題。咱們須要作一些設置。因此爲了省事幹脆用HashRouter
index.js:
import React from 'react'; import ReactDOM from 'react-dom'; // import {BrowserRouter as Router} from 'react-router-dom'; import {HashRouter as Router} from 'react-router-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; //redux import { createStore } from 'redux'; //react-redux(關聯react和redux) import { Provider } from 'react-redux'; //reducers 狀態樹state和邏輯操做 import rootRedux from './rootRedux.js' //建立狀態樹和設置 //生成狀態樹對象 const store = createStore(rootRedux); ReactDOM.render( <Provider store={store}> <Router> <App /> </Router> </Provider> , document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();