React 中的 router -- redux

router

介绍

  • 当应用变得复杂的时候,就需要分块的进行处理和展示,传统模式下,我们是把整个应用分成了多个页面,然后通过 URL 进行连接。
    这种方式也有一些问题,每次切换页面都需要重新发送所有请求和渲染整个页面,不止性能上会有影响,同时也会导致整个 JavaScript 重新执行,丢失状态,所以就出现了路由
  • 优势:有更好的用户体验(减少请求和渲染和页面跳转产生的等待与空白),页面切换快
  • 劣势:首次进入处理慢

基本跳转

它是基于 Web 的 React Router
所以使用的时候需要安转react-router

安装命令:npm i -S react-router-dom
  1. 引入组件BrowserRouter 它是用来在项目中控制路由跳转

index.js文件

import ReactDOM from 'react-dom';
import App from './app'
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
      <App/>
  </BrowserRouter>,
  document.getElementById('root')
);

跟BrowserRouter 相对应的组件还有HashRouter

import ReactDOM from 'react-dom';
import App from './app'
import { HashRouter} from 'react-router-dom';

ReactDOM.render(
  <HashRouter>
      <App/>
  </HashRouter>,
  document.getElementById('root')
);

HashRouter跟BrowserRouter 的区别

  1. 在url中可以看出HashRouter是包含#号的,而BrowerRouter是包含/号的
  2. BrowerRouter类似于Vue中的history模式,HashRouter类似于Vue中的hash模式

app.js文件(配置对应的url地址跳转)

import React from 'react'
import {Route} from 'react-router-dom'
import Home from './view/index'
import About from './view/about'
//引入Nav组件 (这个组件里面是配置跳转后对应的信息的组件)
import Nav from './component/nav'

function App(){
   return (
       <div className="App">
           {/*exact : 属性表示路由使用 精确匹配模式,非 exact 模式下 '/' 匹配所有以 '/' 开头的路由  */}
           {/* path 匹配对应的URL */}
           <Route path='/' exact component={Home}/>
           {/* render 属性来指定渲染函数,render 属性值是一个函数,当路由匹配的时候指定该函数进行渲染 */}
           <Route path='/About' exact render={()=>{
               return  <About/> 
           }}/>
           {/* link组件,他解析出来就是a标签,但是他自带的阻止a标签的默认行为,改变了url由路由处理*/}
           <Nav></Nav>
       </div>
   )
}
export default App

Nav文件

import React from 'react'
// import {Link} from 'react-router-dom'
// NavLink 与 Link 类似,但是它提供了两个特殊属性用来处理页面导航 
// 1.activeStyle:当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式
// 2.activeClassName :当前 URL 与 NavLink 中的 to 匹配的时候,激活 className 中的样式
import {NavLink} from  'react-router-dom'

export default function Nav(){
    return (
        <nav>
            {/* <Link to="/">首页</Link>
            <span>|</span>
            <Link to="/About">关于</Link> */}
            <NavLink 
            to="/"
            activeStyle={ {color:'red'} }
            activeClassName="home"
            exact
            >首页</NavLink>
            <span>|</span>
            <NavLink 
            to="/About"
            exact
            activeStyle={ {color:'yellow'} }
            activeClassName="about"
            >关于</NavLink> 
        </nav>
    )
}

到这里基本的路由跳转就完了

Switch属性

创建一个page404.js组件(随便弄一点内容来显示)

import React from 'react'
function a(){
    return <div>页面没了</div>
}
export default a

引入到app.js文件中

import React,{useState} from 'react'
// 引入Switch:该组件只会渲染首个被匹配的组件
import {Route,Switch} from 'react-router-dom'
import Home from './view/index'
import About from './view/about'
import Nav from './component/nav'
import Page404 from './view/page'

function App(){
    let  [user, setUse] = useState('router')
   return (
       <div className="App">
          <Switch> 
               {/* 只渲染page页面 */}
           <Page404 component={Page404}/>
           <Route path='/' exact component={Home}/>
           <Route path='/About' exact render={()=>{
               return  <About/> 
           }}/>
           <Nav></Nav>
          </Switch> 
       </div>
   )

}
export default App

props传参

import React,{useState} from 'react'

let  [user, setUse] = useState('router')

<Route path='/About' exact render={()=>{
       return  <About user={user} setUse={setUse} /> 
  }}/>

接收
这是在About组件中传的参所以去About组件中接收

import React from 'react'
function About(props) {
    console.log(props);
    let {user, setuse} = props;
    return <h1>关于</h1>
}
export default About

路由参数

  1. history : 历史记录以及路由给我们的一些操作
  2. location : 获取当前URL的一些信息
    pathname : 当前的URL
    search : 接口参数
    state : 跳转路由时,传递的参数
  3. match : 当前路由匹配的相关规则
    params : 动态路由传过来的参数
import React from 'react'
function Home(props){
    console.log(props);
    let {history}=props
    return <div>
            <h1>首页</h1>
            <button onClick={()=>{
                goBack()
                // history里面的方法
                    // history.go(-1)
                    // goBack 后退一步(常用)
                    // goForword 前进一步
                    history.goBack()
                    // history.push('url')
                    // push:修改当前的url(常用)
                    // replace:修改当前的url
                    // history.push("/Cont")
                    // history.replace('/About')
            }
            }>点击</button>
        </div>
}
export default Home

hooks (Router5.0之后出现的)

  • 不能在类组件内使用
  • useHistory : 获取History对象
  • useLocation : 获取Location对象
  • useParams : 获取Params
  • useRouteMatch : 获取Match

withRouter(高阶组件,高阶函数,高阶路由)

作用:不是刚创建的组件都会有路由对象,刚创建的路由里面打印props是空对象 如果你加上withRouter组件后就会有路由对象

import React from 'react'
// 如果一个组件不是路由绑定组件,那么该组件的 props 中是没有路由相关对象的,
// 虽然我们可以通过传参的方式传入,但是如果结构复杂,这样做会特别的繁琐。
// 我们可以通过 withRouter 方法来注入路由对象
import {withRouter,useHistory,useLocation,useParams,useRouteMatch} from 'react-router-dom'
import Inner from './inner'
function Cont(props){
    console.log(props);
    
    console.log(useHistory());//获取History对象
    console.log(useLocation());//获取Location对象
    console.log(useParams());//获取Params
    console.log(useRouteMatch());//获取Match
    let {goBack}=useHistory()
    return  <div>
        <Inner/>
        <h1>详情</h1>
        <button onClick={
            ()=>{
                goBack()
            }
        }>点击触发goBack</button>
        </div>
}
export default withRouter(Cont)

介绍Redux

  • redux与vuex一样是一个组件的状态(数据)管理器,当我们需要在项目各组件中共享数据时可以使用
  • redux是一个第三方的库,本身和react没有任何关系,react-redux也是一个第三方库,可以帮助我们在react项目中更好的使用redux

Redux的使用

组成:

  1. action 操作方法(用户通过界面进行触发方法)
  2. reducer 方法具体实现(用来改变state数据)
  3. state 存放数据 (所有数据集中存放的地方)
  4. view(整个应用组件界面)

简单使用

  • 安装命令

     	npm install redux
    
  • 安装完成后你需要引入redux文件

引入redux
createStore是存放数据的地方

import {createStore} from 'redux'

创建一个仓库

//reducer是下面创建的reducer纯函数
let store=createStore(reducer)

创建一个reducer的纯函数

  • 纯函数:给固定的输入,就一定会有固定的输出,并且不会有任何副作用 所以对于异步函数(定时器、ajax数据请求等)、动态时间都不适意在reducer里使用
  • reducer的参数1:state的初始值 参数2:action 修改的值
// function reducer(state=默认值(也可以是外面传的值), action){}
function reducer(state={name:'王',age:20},action){
    return state
}

打印store

console.log(store)
//会有这4种方法
// dispatch: ƒ dispatch(action) :会发起一次修改(同步,会立即执行)
// getState: ƒ getState():获取状态
// replaceReducer: ƒ replaceReducer(nextReducer)
// subscribe: ƒ subscribe(listener):监听状态的修改

到这里基本的了解就ok了 ,下面我们来看一个案例理解一下

import React from 'react'
import {createStore} from 'redux'
function reducer(state={name:'王',age:20},action){
  // 做判断
  switch(action.type){
    // 如果是name
    case 'name':
      // 返回你修改后的name值
      return{
        ...state,
        name:action.name
      }
      // 如果是age
    case 'age':
      // 返回你修改后的age值
      return{
        ...state,
        age:action.age
      }
  }
    return state
}
// createStore(reducer)用来创建一个仓库,在仓库中对我们的状态进行管理
let store=createStore(reducer)
console.log(store);
// state改变时触发subscribe
// 它里面的参数是 触发时执行的回调
store.subscribe(()=>{
  console.log(store.getState());
})
// 修改name
store.dispatch({
  type:'name',
  name:'李'
})
// 修改age
store.dispatch({
  type:'age',
  age:21
})
function App(){
  return <div>哈哈</div>
}
export default App;

在这里看到的打印效果是 李 和 21 ,因为的默认值是 王 20 之后你做了修改 就变成了 李 和 21

combineReducers合并

  • 随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分
  • 最后拆分的部分都要在reducer中使用所以你就得把你拆分的部分个合并到一起

看个案例理解一下

import React from 'react'
import {createStore,combineReducers} from 'redux'
function index(state={
  info:'首页'
},action){
      switch(action.type){
      case 'index_info':
        return{
          ...state,
          info:action.info
        }
    }
    return state
}
function list(state={info:'列表'},action){
      switch(action.type){
      case 'index_list':
        return{
          ...state,
          info:action.info
        }
      case 'index_message':
          return{
            ...state,
            message:action.message
          }
    }
    return state
}
// 原生的合并方法
// function reducer(state={},action){
//   return {
//     index:index(state.index,action),
//     list:list(state.list,action),
//   }
// }

// 自带的合并方法
// 参数是:传入一个对象,这个对象中的属性,就是要合并的reducer
// 注意:对象中的属性名,要和函数名相同
let reducer=combineReducers({
  index,
  list
})

let store=createStore(reducer)

store.subscribe(()=>{
  console.log(store.getState());
})
store.dispatch({
  type:'index_info',
  info:'我是index的info'

})
store.dispatch({
  type:'index_list',
  info:'我是list的info'
})
store.dispatch({
  type:'index_message',
  message:'我是list的message'
})

function App(){
  return <div></div>
}
export default App;

以上是redux的简单使用,我们接下来看下redux跟react的联合使用

redux和react的联合使用

  • 因为react-redux也是一个第三方库所以它也需要安转一个插件
    react-redux 提供了两个重要的对象, Provider(传值) 和 connect (接收Provider传的值)
    安装命令

      npm install --save react-redux
    

你可以创建一个store库的文件
在这里插入图片描述

index.js

import {createStore,combineReducers} from 'redux'
//引入数据文件
import data from './reducer'
export default createStore(combineReducers({data}))

reducer.js

function data(state={
    name:'王',
    age:20
},action){
    switch(action.type){
        case "name":
            return{
                ...state,
                name:action.name
            }
    }
    return state
}
export default data

在入口文件中引入react-redux

import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux'
// 引入合并文件
import store from './store/index'

ReactDOM.render(
  // 使用store属性接收
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

App.js

import React,{Fragment} from 'react'
import {connect} from 'react-redux'
function Inner(props){
    console.log(props);
    let {name,age,dispatch}=props
    return (   
        <Fragment>
            <p>name:{name}</p>
            <p>age:{age}</p>
            <button onClick={
                ()=>{
                    dispatch({
                        type:'name',
                        name:'我被修改了'
                    })
                }
            }>修改</button>
        </Fragment>
    )
}
//  哪个组件中需要使用redux中的数据的话,就在哪个组件中使用
// connect(state的处理函数)(组件)
    // state的处理函数:(state,[props])=>{
    //     return 要传给组件的数据
    // }

    
export default connect((state,props)=>{
    console.log(state);
    return state.data
})(Inner)


因为以上的方式有可能会绕晕你所有react-redux还出了一下的方式

Hoosk react-redux 7之后才有hooks

  • useSelector(回调函数) 通过回调函数的返回值,来获取state
  • useStore() 直接获取整个仓库
  • useDispatch 获取仓库中的dispatch()方法
    使用

跟上面是一样的效果

import React,{Fragment} from 'react'
import {useSelector,useStore,useDispatch} from 'react-redux'

function Inner(props){
    console.log(props);
    // useSelector个方法里面必须传一个参数  打印出来你会看到数据在data中存着
    // console.log(useSelector((state)=>{
    //     return state
    // }));
    let {name,age}=useSelector((state)=>{
        return state.data
    })
    // console.log(useDispatch);
    let dispatch=useDispatch()
    return (   
        <Fragment>
            <p>name:{name}</p>
            <p>age:{age}</p>
            <button onClick={
                ()=>{
                    dispatch({
                        type:'name',
                        name:'我被修改了'
                    })
                }
            }>修改</button>
        </Fragment>
    )
}
export default Inner

总结:

  • redux的使用就是简单的几部
  1. 引入
import {createStore} from 'redux'
  1. 创建store
let store=createStore(reducer)
  1. 声明reducer函数
function reducer(state=默认值(也可以是外面传的值), action){}

就ok了

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值