Shu-How Zの小窝

Loading...

尚硅谷React教程

尚硅谷React教程(已加更新版内容,B站最火)

https://www.bilibili.com/video/BV1wy4y1D7JT

P1 001_尚硅谷react教程_react简介

react-router

pubsub 怕沙

redux 绿丢

ant-design 安的塞

1.原生JavaScript操作DOM繁琐、效率低(DOM-API操作UI)。
2.使用JavaScript直接操作DOM,浏览器会进行大量的重绘重排。
3,原生JavaScript没有组件化编码方案,代码复用率低。

React的特点
1.采用组件化模式、声明式编码,提高开发效率及组件复用率。
2.在React Native中可以使用React语法进行移动端开发。
3,使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互。

学习React之前你要掌握的JavaScript基础知识
判断this的指向
class(类)
ES6语法规范
npm包管理器
原型、原型链
数组常用方法
模块化

英文官网:https://reactjs.org/
中文官网:https://react.docschina.org/

react developer tools 4.9.0 component 组件 profiler性能

美团 react写的

P2 002_尚硅谷react教程_hello_react案例
P3 003_尚硅谷react教程_虚拟DOM的两种创建方式
P4 004_尚硅谷react教程_虚拟DOM与真实DOM
P5 005_尚硅谷react教程_jsx语法规则
P6 006_尚硅谷react教程jsx小练习
P7 007_尚硅谷react教程_组件与模块
P8 008_尚硅谷react教程_开发者工具的安装
P9 009_尚硅谷react教程_函数式组件
P10 010_尚硅谷react教程_复习类相关知识

函数式组件 类式组件:

旧版16.8

P11 011-尚硅谷react教程-类式组件
P12 012-尚硅谷react教程-对state的理解
P13 013-尚硅谷react教程-初始化state
P14 014_尚硅谷react教程_react中的事件绑定
P15 015-尚硅谷react教程_类中方法中的this
P16 016-尚硅谷react教程-解决类中this指向问题


P17 017-尚硅谷react教程-setState的使用

P18 018-尚硅谷react教程-state的简写方式

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Item extends Component {
    state = {  } 
    constructor(props){
        super(props)
        // 一:
        // this.handleClick=this.handleClick.bind(this) //不在标签绑定this  这性能好
    }
    shouldComponentUpdate(nextProps,nextState){
        //性能优化
        if(nextProps.content!==this.props.content){
            return true
        }else{
            return false
        }
    }
    render() { 
        return (
            <li onClick={this.handleClick}>{this.props.avname}-{this.props.content}</li>
        );
    }
    //一:
    // handleClick(){
    //     this.props.deleteItem(this.props.index)
    // }
    //二:
    handleClick=()=>{
        this.props.deleteItem(this.props.index)
    }
}
Item.propTypes={
    content:PropTypes.string.isRequired,
    index:PropTypes.number,
    deleteItem:PropTypes.func
}
Item.defaultProps={
    avname:'koo'
}
export default Item;

P19 019-尚硅谷react教程_总结state
P20 020-尚硅谷react教程-props的基本使用

我是用类定义的组件(适用于【复杂组件】的定义)有state

我是用函数定义的组件(适用于1简单组件】的定义)无state

hooks 候s

onClick={this.demo()} 立即调用 去掉()才点击生效

P21 021_尚硅谷react教程_批量传递props

let obj={name:'koo',age:18}
<Person {...obj}/>

P22 022-尚硅谷react教程_对props进行限制_

低版本 propTypes内置15.x 16.x需要引入

P23 023_尚硅谷react教程_props的简写方式
P24 024_尚硅谷react教程_类式组件中的构造器与pr...

P25 025-尚硅谷react教程_函数式组件使用props

function Item(props){
    return (
        <div>{props.content}</div>
    )
}
Item.propTypes={
    content:PropTypes.string.isRequired,
    index:PropTypes.number,
    deleteItem:PropTypes.func
}
Item.defaultProps={
    avname:'koo'
}

P26 026_尚硅谷react教程_总结props


P27 027_尚硅谷react教程_字符串形式的ref
P28 028_尚硅谷react教程_回调形式的ref

P29 029_尚硅谷react教程_回调ref中调用次数的问题

1.ref="string"
2.<ul ref={ul=>this.ul=ul}> 这种多 但是更新state调用俩次
3.<button ref={this.saveClick}>onClick</button>
saveClick(e){
        this.btn=e
    }

P30 030-尚硅谷react教程-createRef的使用

4.btnRef=React.createRef() //只能一个
<button ref={this.btnRef}>onClick</button>

P31 031_尚硅谷react教程_总结ref
P32 032-尚硅谷react教程_react中的事件处理
P33 033-尚硅谷react教程-非受控组件
P34 034_尚硅谷react教程_受控组件
P35 035_尚硅谷react教程_高阶函数_函数柯里化
P36 036_尚硅谷react教程_不用柯里化的写法

P37 037_尚硅谷react教程_引出生命周期

ReactDOM.unmountComponentAtNode(document.getElementById('test')) 卸组件

React生命周期旧版

P38 038_尚硅谷react教程_生命周期(旧)_组件挂载...1
P39 039_尚硅谷react教程_生命周期(旧)_setState流程1
P40 040_尚硅谷react教程_生命周期(旧)_forceUpda...0


P41 041_尚硅谷react教程_生命周期(旧)_父组件ren...1
P42 042_尚硅谷react教程_总结生命周期(旧)

P43 043-尚硅谷react教程-对比新旧生命周期

react17.0.1

React生命周期新版

去掉3个

除了componentWillUNmount 其他带will的钩子都要UNSFAE_

16.x还可以用 17.x不可用+

废弃三个 新增俩个 俩个少用

P44 044-尚硅谷react教程_getDerivedStateFromPro...1

static getDerivedStateFromProps(props,state){
    return null //state object
}

P45 045-尚硅谷react教程-getSnapshotBeforeUpdate 1

getSnapshotBeforeUpdate 在更新前 获取快照

getSnapshotBeforeUpdate(prevProps,prevState){
    return null
}
conponentDidUpdate(prevProps,prevState,snapshotValue){
}

P46 046-尚硅谷react教程-getSnapshotBeforeUpda 1
P47 047_尚硅谷react教程_总结生命周期(新)
P48 048-尚硅谷react教程-DOM的diffing算法
P49 049_尚硅谷react教程_初始化react脚手架
P50 050-尚硅谷react教程_脚手架文件介绍_public

create-react-app@4.0.0 视频的版本

P51 051_尚硅谷react教程_脚手架文件介绍_src

reportWebVitals.js 记录页面性能的

setupTest.js 单元测试的 组件测试

P52 052_尚硅谷react教程_一个简单的Hello组件

P53 053_尚硅谷react教程_样式的模块化

Koo.module.css 文件改名
import KooCss from './Koo.module.css'
<div className={KooCss.title}>调用css</div>
.title{
    color: red;
}

P54 054_尚硅谷react教程-vscode中react插件的安装

vscode ES7 React/Redux/GraphQL/React-Native snippets 插件

rcc打入 快捷键

src
	components
    	Home
        	Home.js
		    Home.css

P55 055_尚硅谷_react教程_组件化编码流程
P56 056_尚硅谷_react教程_TodoList案例_静态组件
P57 057_尚硅谷_react教程_TodoList案例_动态初始.
P59 059_尚硅谷_react教程_TodoList案例_鼠标移入.
P60 060_尚硅谷_react教程_TodoList案例_添加一个.
P58 058_尚硅谷_react教程_TodoList案例_添加todo

<input defaultChecked={true}/>
一上来就勾选 以后可以改
checked 写死了 不能改 要写onClick才可以改

<div onMouseEnter={this.hanle(true)}></div>
hanle(flag){
	return ()=>{}
}

uuid npm i -S nanoid

P61 061_尚硅谷_react教程_TodoList案例_对props...(

yarn add prop-types

P62 062_尚硅谷_react教程_TodoList案例_删除一个...1
P63 063-尚硅谷_react教程_TodoList案例_实现底部...2
P64 064_尚硅谷_react教程_TodoList案例_总结Todo...

P65 065_尚硅谷_react教程_脚手架配置代理_方法1 2

  "proxy":"http://127.0.0.1:5000"
package.json 加入 代理
src
setupProxy.js

const proxy=require('http-proxy-middleware')
module.exports=function(app){
    app.use(
        proxy('/api',{
            target:'http://127.0.0.1:5000',
            changeOrigin:true,
            pathRewrite:{'^/api1':''}
        })
    )
}

P66 066_尚硅谷_react教程_脚手架配置代理_方法2 2
P67 067_尚硅谷_react教程_github搜索案例_静态组件1
P68 068_尚硅谷_react教程_github搜索案例_axios...2
P69 069_尚硅谷_react教程_github搜索案例_展示数据1
P70 070_尚硅谷_react教程_github搜索案例_完成案例2


P71 071_尚硅谷_react教程_消息订阅与发布技_pub...

工具库:PubSubJS npm i -S pubsub-js 兄弟组件通讯

https://github.com/mroderick/PubSubJS

import React, { Component,Fragment } from 'react'
import Home from './components/Home/Home.js'
import Item from './components/Item/Item.js'

export default class App extends Component {
  render() {
    return (
      <Fragment>
        <Home></Home>
        <Item></Item>
      </Fragment>
    )
  }
}
import React, { Component } from 'react'
import PubSub from 'pubsub-js'

export default class Home extends Component {
  componentDidMount(){
    this.token=PubSub.subscribe('go',(msg,data)=>{
      console.log(data)
    })
  }
  componentWillUnmount(){
    PubSub.unsubscribe(this.token)
  }
  render() {
    return (
      <div>Home</div>
    )
  }
}

import React, { Component } from 'react'
import PubSub from 'pubsub-js'

export default class Item extends Component {
  componentDidMount(){
    PubSub.publish('go','hello react')
  }
  render() {
    return (
      <div>Item</div>
    )
  }
}

P72 072_尚硅谷_react教程_fetch发送请求
fetch fa起

_P73 073_尚硅谷_react教程_总结github搜索案例

P74 074_尚硅谷_react教程_对SPA应用的理解

.SPA的理解
单页Web应用(single page web application,SPA).
整个应用只有一个完整的页面。
点击页面中的链接不会刷新页面,只会做页面的局部更新。数据都需要通过 ajax 请求获取,并在前端异步展现。

P75 075_尚硅谷_react教程_对路由的理解
P76 076_尚硅谷_react教程_前端路由原理

P77 077_尚硅谷_react教程_路由的基本使用

docschina.org

react-router.docschina.org/web/guides/philosophy

http://react-router.docschina.org/web/guides/philosophy

yarn add react-router-dom@5

俩种路由

import React, { Component,Fragment } from 'react'
import Home from './components/Home/Home.js'
import Item from './components/Item/Item.js'
import { Link,BrowserRouter,Route } from 'react-router-dom'

export default class App extends Component {
  render() {
    return (
      <Fragment>
          <Link to="/about">About</Link>
          <Link to="/home">Home</Link>
          <Route path="/about" component={Item}></Route>
          <Route path="/home" component={Home}></Route>
      </Fragment>
    )
  }
}
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

P78 078_尚硅谷_react教程_路由组件与一般组件

P79 079_尚硅谷_react教程_NavLink的使用

import { Link,NavLink,BrowserRouter,Route } from 'react-router-dom'
<NavLink to="/about">About</NavLink>
NavLink 点谁加active类 默认
<NavLink activeClassName="active" to="/home">Home</NavLink> diy
index.jsx 文件

P80 080_尚硅谷_react教程_封装NavLink组件

82

import React, { Component,Fragment } from 'react'
import Home from './components/Home/Home.js'
import Item from './components/Item/Item.js'
import { Link,NavLink,BrowserRouter,Route } from 'react-router-dom'
import MyLink from './components/MyLink/index.jsx'

export default class App extends Component {
  render() {
    return (
      <Fragment>
          {/* <NavLink activeClassName="active" to="/about">About</NavLink>
          <NavLink activeClassName="active" to="/home">Home</NavLink> */}
          <MyLink to="/about">About</MyLink>
          <MyLink to="/home">Home</MyLink>
          <Route path="/about" component={Item}></Route>
          <Route path="/home" component={Home}></Route>
      </Fragment>
    )
  }
}
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom/cjs/react-router-dom.min'

export default class MyLink extends Component {
  render() {
    return (
        //children 标签中间文字 属性在 this.props  navlink有children属性
        <NavLink activeClassName="active" {...this.props}/>
    )
  }
}

P81 081_尚硅谷_react教程_Switch的使用

import React, { Component,Fragment } from 'react'
import Home from './components/Home/Home.js'
import Item from './components/Item/Item.js'
import { Link,NavLink,BrowserRouter,Route,Switch } from 'react-router-dom'
import MyLink from './components/MyLink/index.jsx'
import Test from './components/Test/index.jsx'

export default class App extends Component {
  render() {
    return (
      <Fragment>
          {/* <NavLink activeClassName="active" to="/about">About</NavLink>
          <NavLink activeClassName="active" to="/home">Home</NavLink> */}
          <MyLink to="/about">About</MyLink>
          <MyLink to="/home">Home</MyLink>
          <Switch>
            <Route path="/about" component={Item}></Route>
            <Route path="/home" component={Home}></Route>
            {/* 加switch组件一匹配了就不在继续 匹配相同 */}
            <Route path="/home" component={Test}></Route>
          </Switch>
      </Fragment>
    )
  }
}

Switch的使用
1.通常情况下,path和component是一一对应的关系。
2.Switch可以提高路由匹配效率(单一匹配)。

P82 082_尚硅谷_react教程_解决样式丢失问题

_P83 083_尚硅谷_react教程_路由的模糊匹配与严格...1

            {/* exact={true}精确匹配 不随便开 东西不对才开  默认模糊匹配 */}
            <Route exact={true} path="/home" component={Home}></Route>

P84 084_尚硅谷_react教程_Redirect的使用

import { Link,NavLink,BrowserRouter,Route,Switch,Redirect } from 'react-router-dom'
<Redirect to="/home"/>

.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由

P85 085_尚硅谷_react教程_嵌套路由

import React, { Component,Fragment } from 'react'
import PubSub from 'pubsub-js'
import MyLink from '../MyLink'
import { Route,Switch,Redirect } from 'react-router-dom/cjs/react-router-dom.min'
import New from './New'
import Blog from './Blog'

export default class Home extends Component {
  componentDidMount(){
    // console.log(this.props)//路由传递一些东西

    this.token=PubSub.subscribe('go',(msg,data)=>{
      console.log(data)
    })
  }
  componentWillUnmount(){
    PubSub.unsubscribe(this.token)
  }
  render() {
    return (
      <Fragment>
        <div>Home</div>
        <ul>
          <li><MyLink to="/home/new">new</MyLink></li>
          <li><MyLink to="/home/blog">blog</MyLink></li>
        </ul>
        <Switch>
          <Route path="/home/new" component={New}></Route>
          <Route path="/home/blog" component={Blog}></Route>
          <Redirect to="/home/new"/>
        </Switch>
      </Fragment>
    )
  }
}

P86 086_尚硅谷_react教程_向路由组件传递params...2

params

ajax query params body-urlencode-json

import React, { Component } from 'react'
import { Route,Switch,Redirect } from 'react-router-dom/cjs/react-router-dom.min'
import MyLink from '../../MyLink'
import Detail from './Detail'

export default class Blog extends Component {
  state={
    msg:[
      {id:1,title:'vue'},
      {id:2,title:'react'},
      {id:3,title:'angular'}
    ]
  }
  render() {
    return (
      <div>
        {
          this.state.msg.map(item=>{
            return (
              <div key={item.id}> 
                <MyLink to={`/home/blog/detail/${item.id}/${item.title}`}>{item.title}</MyLink>
              </div>
            )
          })
        }
        <Switch>
          <Route path="/home/blog/detail/:id/:title" component={Detail}></Route>
        </Switch>
      </div>
    )
  }
}

import React, { Component } from 'react'

export default class Detail extends Component {
  render() {
    let {id,title} = this.props.match.params
    return (
      <div>id:{id}-title:{title}</div>
    )
  }
}

P87 087_尚硅谷_react教程_向路由组件传递search...1

import qs from 'querystring' 
urldecedo编码 和对象互转 
import React, { Component } from 'react'
import qs from 'querystring'

export default class Detail extends Component {
  render() {
    // let {id,title} = this.props.match.params
    let search=this.props.location.search
    let {id,title}=qs.parse(search.slice(1))
    return (
      <div>id:{id}-title:{title}</div>
    )
  }
}

import React, { Component } from 'react'
import { Route,Switch,Redirect } from 'react-router-dom/cjs/react-router-dom.min'
import MyLink from '../../MyLink'
import Detail from './Detail'

export default class Blog extends Component {
  state={
    msg:[
      {id:1,title:'vue'},
      {id:2,title:'react'},
      {id:3,title:'angular'}
    ]
  }
  render() {
    return (
      <div>
        {
          this.state.msg.map(item=>{
            return (
              <div key={item.id}> 
                {/* params参数 */}
                {/* <MyLink to={`/home/blog/detail/${item.id}/${item.title}`}>{item.title}</MyLink> */}
                {/* search参数 */}
                <MyLink to={`/home/blog/detail?id=${item.id}&title=${item.title}`}>{item.title}</MyLink>
              </div>
            )
          })
        }
        <Switch>
          {/* params参数 */}
          {/* <Route path="/home/blog/detail/:id/:title" component={Detail}></Route> */}
          {/* search参数 */}
          <Route path="/home/blog/detail" component={Detail}></Route>
        </Switch>
      </div>
    )
  }
}

P88 088_尚硅谷_react教程_向路由组件传递state参数1

import React, { Component } from 'react'
import { Route,Switch,Redirect } from 'react-router-dom/cjs/react-router-dom.min'
import MyLink from '../../MyLink'
import Detail from './Detail'

export default class Blog extends Component {
  state={
    msg:[
      {id:1,title:'vue'},
      {id:2,title:'react'},
      {id:3,title:'angular'}
    ]
  }
  render() {
    return (
      <div>
        {
          this.state.msg.map(item=>{
            return (
              <div key={item.id}> 
                {/* params参数 */}
                {/* <MyLink to={`/home/blog/detail/${item.id}/${item.title}`}>{item.title}</MyLink> */}
                {/* search参数 */}
                {/* <MyLink to={`/home/blog/detail?id=${item.id}&title=${item.title}`}>{item.title}</MyLink> */}
                {/* state参数 刷新还在 history记录*/}
                <MyLink to={{pathname:'/home/blog/detail',state:{id:item.id,title:item.title}}}>{item.title}</MyLink>
              </div>
            )
          })
        }
        <Switch>
          {/* params参数 */}
          {/* <Route path="/home/blog/detail/:id/:title" component={Detail}></Route> */}
          {/* search参数 or state 不用带其他*/}
          <Route path="/home/blog/detail" component={Detail}></Route>
        </Switch>
      </div>
    )
  }
}

import React, { Component } from 'react'
// import qs from 'querystring'

export default class Detail extends Component {
  render() {
    // params参数
    // let {id,title} = this.props.match.params
    // search参数
    // let search=this.props.location.search
    // let {id,title}=qs.parse(search.slice(1))
    //state参数 刷新还在 history记录 清除缓存 加{}处理
    let {id,title}=this.props.location.state||{}
    return (
      <div>id:{id}-title:{title}</div>
    )
  }
}

P89 089_尚硅谷_react教程_总结路由参数
1.params 2.search 3.state 顺序用 多用

_P90 090_尚硅谷_react教程_push与repalce
87

{/* replace={true} 默认push跳转 */}
                <MyLink replace={true} to={{pathname:'/home/blog/detail',state:{id:item.id,title:item.title}}}>{item.title}</MyLink>
              </div>

P91 091_尚硅谷_react教程_编程式路由导航

import React, { Component } from 'react'
import { Route,Switch,Redirect } from 'react-router-dom/cjs/react-router-dom.min'
import MyLink from '../../MyLink'
import Detail from './Detail'

export default class Blog extends Component {
  state={
    msg:[
      {id:1,title:'vue'},
      {id:2,title:'react'},
      {id:3,title:'angular'}
    ]
  }
  pushShow=(id,title)=>{
    console.log(this.props)
    // this.props.history.push(`/home/blog/detail/${id}/${title}`) //params
    // this.props.history.push(`/home/blog/detail?id=${id}&title=${title}`) //search
    this.props.history.push(`/home/blog/detail`,{id,title})  //state
  }
  replaceShow=(id,title)=>{
    return ()=>{
      this.props.history.replace(`/home/blog/detail`,{id,title}) 
    }
  }
  handle=()=>{
    // this.props.history.go(-2) //go -1 2
    // this.props.history.goBack()
    this.props.history.goForward()
  }
  render() {
    return (
      <div>
        {
          this.state.msg.map(item=>{
            return (
              <div key={item.id}> 
                {/* params参数 */}
                {/* <MyLink to={`/home/blog/detail/${item.id}/${item.title}`}>{item.title}</MyLink> */}
                {/* search参数 */}
                {/* <MyLink to={`/home/blog/detail?id=${item.id}&title=${item.title}`}>{item.title}</MyLink> */}
                {/* state参数 刷新还在 history记录*/}
                {/* replace={true} 默认push跳转 */}
                <MyLink  to={{pathname:'/home/blog/detail',state:{id:item.id,title:item.title}}}>{item.title}</MyLink>
                <button onClick={()=>this.pushShow(item.id,item.title)}>push</button>
                <button onClick={this.replaceShow(item.id,item.title)}>replace</button>
              </div>
            )
          })
        }
        <Switch>
          {/* params参数 */}
          {/* <Route path="/home/blog/detail/:id/:title" component={Detail}></Route> */}
          {/* search参数 or state 不用带其他*/}
          <Route path="/home/blog/detail" component={Detail}></Route>
        </Switch>
        <button onClick={this.handle}>操作</button>
      </div>
    )
  }
}

P92 092-尚硅谷_react教程_withRouter的使用

withRouter可以加工一般组件,让:一般组件具备路由组件所特有的API

import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'

class Header extends Component {
    handle = () => {
        // this.props.history.go(-2) //go -1 2
        this.props.history.goBack()
        // this.props.history.goForward()
    }
    render() {
        return (
            <div>
                Header
                <button onClick={this.handle}>操作</button>
            </div>
        )
    }
}

export default withRouter(Header)

P93 093-尚硅谷_react教程_BrowserRouter与Hash...

:十三、BrowserRouter 与HashRouter的区别
1.底层原理不一样:
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。
2.url表现形式不一样
BrowserRouter的路径中没有#,例如:localhost:3000/demo/test HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3,刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中.
(2).HashRouter刷新后会导致路由state参数的丢失。
4,备注:HashRouter可以用于解决一些路径错误相关的问题。


P94 094_尚硅谷_react教程_antd的基本使用

material-ui 国外

ant-design 国内蚂蚁金服 : https://ant.design/index-cn

视频ant-design4.0

管理系统多用

npm install antd --save

新版不用引入css

P95 095_尚硅谷_react教程_antd样式的按需引入

3.x版本按需引入

5.x tree shake

yarn eject 暴露webpack配置文件

https://ant-design.antgroup.com/docs/react/use-with-create-react-app-cn

P96 096_尚硅谷_react教程_antd自定义主题

P97 097_尚硅谷_react教程_redux简介

pubsub怕沙 redux绿大x

.redux 是什么
1.redux 是一个专门用于做状态管理的 JS 库(不是 react 插件库)。
2.它可以用在react,angular,vue等项目中,但基本与react配合使用。+
3.作用:集中式管理 react 应用中多个组件共享的状态。

http://www.redux.org.cn/

同vuex 能不用就不用 吃力时用

P98 098_尚硅谷_react教程_redux工作流程
redux

redux

action reducer store components


_P99 099_尚硅谷_react教程_求和案例_纯react版

P100 100_尚硅谷_react教程_求和案例_redux精简版

传参数 事件用箭头函数内联 方法用高阶函数

yarn install redux

带s的可以有多个actions reduces

1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)

reducer 纯函数

store.subscribe redux状态改变都调用这个回调函数
this.setState({}) 空对象也更新 shouldComponentUpdate阀门控制下性能
Count component
import React, { Component } from 'react'
import store from '../../redux/store'

export default class Count extends Component {
    // componentDidMount(){
    //     store.subscribe(()=>{
    //         this.setState({})
    //     })
    // }
    inc=()=>{
        let value= this.select.value
        store.dispatch({type:'inc',data:value*1})
    }
    deinc=()=>{
        let value= this.select.value
        store.dispatch({type:'deinc',data:value*1})
    }
    incifodd=()=>{
        let value= this.select.value
        let count=store.getState()
        if(count%2!==0){
            store.dispatch({type:'inc',data:value*1})
        }
    }
    asyncinc=()=>{
        let value= this.select.value
        setTimeout(() => {
            store.dispatch({type:'inc',data:value*1})
        }, 500);
    }
    render() {
        return (
            <div>
                <h1>current num:{store.getState()}</h1>
                <div>
                    <select ref={select=>this.select=select}>
                        <option value="1">1</option>
                        <option value="2">2</option>
                    </select>
                    &nbsp;
                    <button onClick={this.inc}>inc</button>&nbsp;
                    <button onClick={this.deinc}>deinc</button>&nbsp;
                    <button onClick={this.incifodd}>inc if odd</button>&nbsp;
                    <button onClick={this.asyncinc}>async inc</button>
                </div>
            </div>
        )
    }
}

跟index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <App />
  </React.StrictMode>
);
//不会全部渲染 dom diff 差别的出现
store.subscribe(()=>{
  root.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
  );
})
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

redux/store.js
import { createStore } from "redux";
import count_reducer from "./count_reducer";

export default createStore(count_reducer)
redux/count_reducer.js
let initState=0 //init is undefined
export default function(preState=initState,action){
    let {type,data}=action
    switch (type) {
        case 'inc':
            return preState+data   
        case 'deinc':
            return preState-data                 
        default:
            return preState
    }
}

P101 101_尚硅谷_react教程_求和案例_redux完整版

Count Component
import React, { Component } from 'react'
import store from '../../redux/store'
import { createIncAction,createDeincAction } from '../../redux/count_action'

export default class Count extends Component {
    // componentDidMount(){
    //     store.subscribe(()=>{
    //         this.setState({})
    //     })
    // }
    inc=()=>{
        let value= this.select.value*1
        store.dispatch(createIncAction(value))
    }
    deinc=()=>{
        let value= this.select.value*1
        store.dispatch(createDeincAction(value))
    }
    incifodd=()=>{
        let value= this.select.value*1
        let count=store.getState()
        if(count%2!==0){
            store.dispatch(createIncAction(value))
        }
    }
    asyncinc=()=>{
        let value= this.select.value*1
        setTimeout(() => {
            store.dispatch(createIncAction(value))
        }, 500);
    }
    render() {
        return (
            <div>
                <h1>current num:{store.getState()}</h1>
                <div>
                    <select ref={select=>this.select=select}>
                        <option value="1">1</option>
                        <option value="2">2</option>
                    </select>
                    &nbsp;
                    <button onClick={this.inc}>inc</button>&nbsp;
                    <button onClick={this.deinc}>deinc</button>&nbsp;
                    <button onClick={this.incifodd}>inc if odd</button>&nbsp;
                    <button onClick={this.asyncinc}>async inc</button>
                </div>
            </div>
        )
    }
}

redux/count_action.js
import {INC,DEINC} from './constant'
export const createIncAction=data=>({type:INC,data})
export const createDeincAction=data=>({type:DEINC,data})
redux/count_reducer.js
import {INC,DEINC} from './constant'
let initState=0 //init is undefined
export default function(preState=initState,action){
    let {type,data}=action
    switch (type) {
        case INC:
            return preState+data   
        case DEINC:
            return preState-data                 
        default:
            return preState
    }
}
redux/constant.js
export const INC='inc'
export const DEINC='deinc'

P102 102_尚硅谷_react教程_求和案例_异步action版

yarn add redux-thunk 开启异步action

Count Component
import React, { Component } from 'react'
import store from '../../redux/store'
import { createIncAction,createDeincAction,createIncAsyncAction } from '../../redux/count_action'

export default class Count extends Component {
    // componentDidMount(){
    //     store.subscribe(()=>{
    //         this.setState({})
    //     })
    // }
    inc=()=>{
        let value= this.select.value*1
        store.dispatch(createIncAction(value))
    }
    deinc=()=>{
        let value= this.select.value*1
        store.dispatch(createDeincAction(value))
    }
    incifodd=()=>{
        let value= this.select.value*1
        let count=store.getState()
        if(count%2!==0){
            store.dispatch(createIncAction(value))
        }
    }
    asyncinc=()=>{
        let value= this.select.value*1
        // setTimeout(() => {
        //     store.dispatch(createIncAction(value))
        // }, 500);
        store.dispatch(createIncAsyncAction(value,500))
    }
    render() {
        return (
            <div>
                <h1>current num:{store.getState()}</h1>
                <div>
                    <select ref={select=>this.select=select}>
                        <option value="1">1</option>
                        <option value="2">2</option>
                    </select>
                    &nbsp;
                    <button onClick={this.inc}>inc</button>&nbsp;
                    <button onClick={this.deinc}>deinc</button>&nbsp;
                    <button onClick={this.incifodd}>inc if odd</button>&nbsp;
                    <button onClick={this.asyncinc}>async inc</button>
                </div>
            </div>
        )
    }
}

redux/store.js
import { createStore,applyMiddleware } from "redux";
import count_reducer from "./count_reducer";
import { thunk } from "redux-thunk";

export default createStore(count_reducer,applyMiddleware(thunk))
redux/count_action.js
import {INC,DEINC} from './constant'
//同步action,就是指action的值为Object类型的一般对象
export const createIncAction=data=>({type:INC,data})
export const createDeincAction=data=>({type:DEINC,data})
//异步action,就是指action的值为函数
export const createIncAsyncAction=(data,time)=>{
    return (dispatch)=>{
        setTimeout(()=>{
            dispatch(createIncAction(data))
        },time)
    }
}

P103 103_尚硅谷_react教程_对react-redux的理解

react-redux

P104 104_尚硅谷_react教程_连接容器组件与UI组件

yarn add react-redux

P105 105-尚硅谷_react教程_react-redux基本使用

App.js
import React, { Component,Fragment } from 'react'
import Count from './containers/Count'
import store from './redux/store'

export default class App extends Component {
  render() {
    return (
      <Fragment>
        <Count store={store}></Count>
      </Fragment>
    )
  }
}
src/containers/Count/index.jsx
import CountUI from '../../components/Count'
import { connect } from 'react-redux'
import {createIncAction,createDeincAction,createIncAsyncAction} from '../../redux/count_action'

function mapStateToProps(state){
    return {
        count:state
    }
}
function mapDispatchToProps(dispatch){
    return {
        jia:num=>dispatch(createIncAction(num)),
        jian:num=>dispatch(createDeincAction(num)),
        jiaAsync:(num,time)=>dispatch(createIncAsyncAction(num,time)),
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(CountUI)
src/components/Count/index.jsx
import React, { Component } from 'react'

export default class Count extends Component {

    inc=()=>{
        let value= this.select.value*1
        this.props.jia(value)
    }
    deinc=()=>{
        let value= this.select.value*1
        this.props.jian(value)
    }
    incifodd=()=>{
        let value= this.select.value*1
        if(this.props.count&2!==0){
            this.props.jia(value)
        }
    }
    asyncinc=()=>{
        let value= this.select.value*1
        this.props.jiaAsync(value,500)
    }
    render() {
        return (
            <div>
                <h1>current num:{this.props.count}</h1>
                <div>
                    <select ref={select=>this.select=select}>
                        <option value="1">1</option>
                        <option value="2">2</option>
                    </select>
                    &nbsp;
                    <button onClick={this.inc}>inc</button>&nbsp;
                    <button onClick={this.deinc}>deinc</button>&nbsp;
                    <button onClick={this.incifodd}>inc if odd</button>&nbsp;
                    <button onClick={this.asyncinc}>async inc</button>
                </div>
            </div>
        )
    }
}

P106 106_尚硅谷_react教程_优化1_简写mapDispatch

react-redux api优化简写 api调用

src/containers/Count/index.jsx
import CountUI from '../../components/Count'
import { connect } from 'react-redux'
import {createIncAction,createDeincAction,createIncAsyncAction} from '../../redux/count_action'

export default connect(
    state=>({count:state}),
    {
        jia:createIncAction,
        jian:createDeincAction,
        jiaAsync:createIncAsyncAction,
    }
)(CountUI)

P107 107_尚硅谷_react教程_优化2_Provider组件的..

继续优化

跟/index.js 入口
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store';
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <Provider store={store}>
         <App />
      </Provider>
  </React.StrictMode>
);
// react-redux connect已经检测了
//不会全部渲染 dom diff 差别的出现
// store.subscribe(()=>{
//   root.render(
//     <React.StrictMode>
//         <App />
//     </React.StrictMode>
//   );
// })
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

App.js
import React, { Component,Fragment } from 'react'
import Count from './containers/Count'

export default class App extends Component {
  render() {
    return (
      <Fragment>
        <Count></Count>
      </Fragment>
    )
  }
}

P108 108_尚硅谷_react教程_优化3_整合UI组件与….

叫Component containers 都可以

del src/components/Count/index.jsx
合并在一个文件
src/containers/Count/index.jsx

import { connect } from 'react-redux'
import {createIncAction,createDeincAction,createIncAsyncAction} from '../../redux/count_action'
import React, { Component } from 'react'

class Count extends Component {

    inc=()=>{
        let value= this.select.value*1
        this.props.jia(value)
    }
    deinc=()=>{
        let value= this.select.value*1
        this.props.jian(value)
    }
    incifodd=()=>{
        let value= this.select.value*1
        if(this.props.count&2!==0){
            this.props.jia(value)
        }
    }
    asyncinc=()=>{
        let value= this.select.value*1
        this.props.jiaAsync(value,500)
    }
    render() {
        return (
            <div>
                <h1>current num:{this.props.count}</h1>
                <div>
                    <select ref={select=>this.select=select}>
                        <option value="1">1</option>
                        <option value="2">2</option>
                    </select>
                    &nbsp;
                    <button onClick={this.inc}>inc</button>&nbsp;
                    <button onClick={this.deinc}>deinc</button>&nbsp;
                    <button onClick={this.incifodd}>inc if odd</button>&nbsp;
                    <button onClick={this.asyncinc}>async inc</button>
                </div>
            </div>
        )
    }
}

export default connect(
    state=>({count:state}),
    {
        jia:createIncAction,
        jian:createDeincAction,
        jiaAsync:createIncAsyncAction,
    }
)(Count)

P109 109_尚硅谷_react教程_数据共享-编写Person...
P110 110_尚硅谷_react教程_数据共享-编写Person...

P111 111_尚硅谷_react教程_数据共享_完成数据...

多个reducers
src/containers/Person/index.jsx

import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import { connect } from 'react-redux'
import {createAddPersonAction} from '../../redux/actions/person'

class Person extends Component {
  add=()=>{
    let obj={id:nanoid(),name:this.input.value}
    this.props.addPerson(obj)
  }
  render() {
    return (
      <div>
        <label htmlFor="name">name:</label>
        <input type="text" id='name' ref={input=>this.input=input} />
        <button onClick={this.add}>add</button>
        <p>上方组件和是:{this.props.he}</p>
        <ul>
          {
            this.props.rens.map(item=>{
              console.log(item,222222)
              return (
                <li key={item.id}>{item.name}</li>
              )
            })
          }
        </ul>
      </div>
    )
  }
}

export default connect(
  state=>({rens:state.rens,he:state.he}),
  {
    addPerson:createAddPersonAction
  }
)(Person)

src/redux/store.js
import { createStore,applyMiddleware,combineReducers } from "redux";
import count_reducer from "./reducers/count";
import person_reducer from "./reducers/person";
import { thunk } from "redux-thunk";

let allReducer=combineReducers({
    he:count_reducer,
    rens:person_reducer
})
export default createStore(allReducer,applyMiddleware(thunk))

P112 112_尚硅谷_react教程_纯函数

7.8.纯函数和高阶函数
7.8.1.纯函数
1.一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)
2.必须遵守以下一些约束
1)不得改写参数数据
2)不会产生任何副作用,例如网络请求,输入和输出设备3)不能调用 Date.now)或者 Math.random(等不纯的方法
3.redux的reducer函数必须是一个纯函数

P113 113_尚硅谷_react教程_redux开发者工具

Redux DevTools

安装 yarn add redux-devtools-extension

src/redux/store.js
import { createStore,applyMiddleware,combineReducers } from "redux";
import count_reducer from "./reducers/count";
import person_reducer from "./reducers/person";
import { thunk } from "redux-thunk";
import {composeWithDevTools} from 'redux-devtools-extension'

let allReducer=combineReducers({
    he:count_reducer,
    rens:person_reducer
})
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

P114 114_尚硅谷_react教程_最终版
P115 115_尚硅谷_react教程_项目打包运行

npm run build 打包

npm i serve -g

serve -s build

P116 116_尚硅谷_react教程_扩展1_setState

setState更新状态的2种写法
(1).setState(stateChange,[callback])------对象式的setState
1.stateChange为状态改变对象(该对象可以体现出状态的更改)
2.callback是可选的回调函数,它在状态更新完毕、界面也更新后(render调用后)才被调用
(2).setState(updater,[callback])------函数式的setState
1.updater为返回stateChange对象的函数。
2.updater可以接收到state和props.
4.callback是可选的回调的数,它在状态更新、界面也更新后(render调用后)才被调用。
总结:
1.对象式的setState是函数式的setState的简写方式(语法糖)
2.使用原则:
(1).如果新状态不依赖于原状态 => 使用对象方式
(2).如果新状态依赖于原状态
=>使用函数方式
(3).如果需要在setState()执行后获取最新的状态数据,要在第二个callback函数中读取

import React, { Component } from 'react'

export default class Demo extends Component {
    state = {
        count: 0
    }
    add = () => {
        // this.setState({
        //     count:this.state.count+1
        // },()=>{
        //     console.log(this.state.count) //this.setState异步的 在回调才获取改后的值
        // })
        this.setState((state,props)=>{
            return {
                count:state.count+props.num
            }
        })
    }
    render() {
        return (
            <div>
                <p>Count:{this.state.count}</p>
                <button onClick={this.add}>add</button>
            </div>
        )
    }
}

P117 117_尚硅谷_react教程_扩展2_lazyLoad

路由组件的lazyLoad

import React, { Component, Fragment, lazy, Suspense } from 'react'
// import Home from './Home'
// import Item from './Item'
import { Link, Route } from 'react-router-dom'
import Loading from './Loading'

const Home = lazy(() => import('./Home'))
const Item = lazy(() => import('./Item'))

export default class App extends Component {
    render() {
        return (
            <Fragment>
                <Link to="/about">About</Link>
                <Link to="/home">Home</Link>
                {/* <Suspense fallback={<del>Loading...</del>}></Suspense> 直接写也是虚拟dom 组件 */}
                {/* 只能普通导入组件 请求中显示的 和骨架屏差不多 */}
                <Suspense fallback={<Loading/>}>
                    <Route path="/about" component={Item}></Route>
                    <Route path="/home" component={Home}></Route>
                </Suspense>
            </Fragment>
        )
    }
}

P118 118_尚硅谷_react教程_扩展3_stateHook

1.React Hook/Hooks是什么?
(1).Hook是React 16.8.0版本增加的新特性/新语法(2).可以让你在函数组件中使用 state 以及其他的 React 特性

2.三个常用的Hook
(1).State Hook:React.useState()
(2).Effect Hook:React.useEffect()
(3).Ref Hook:React.useRef()

React.useState render 1+N 底层做了处理

import React from 'react'

export default function Deme(props) {
    let [count,setCount]=React.useState(0)
    let add=()=>{
        // setCount(count+props.num)
        setCount((preCount)=>count+props.num)
    }
    return (
        <div>
            <p>count:{count}</p>
            <button onClick={add}>add</button>
        </div>
    )
}

P119 119_尚硅谷_react教程_扩展4_EffectHook

effecthook相当生命周期 副作用

Demo.js
import React from 'react'
// import ReactDOM from 'react-dom'
import root from '../../index'

export default function Deme(props) {
    let [count,setCount]=React.useState(0)
    // React.useEffect 相当生命周期
    React.useEffect(()=>{
        let timer=setInterval(()=>{
            setCount((count)=>count+1)
        },1000)
        return ()=>{
            //return 相当componentWillUnmount
            clearInterval(timer)
        }
    },[])//不写第二参数 全部检测 [count]检测count相当componentDidUpdate 写[]相当componentDidMount 
    let add=()=>{
        // setCount(count+props.num)
        setCount((preCount)=>count+props.num)
    }
    let unmount=()=>{
        // ReactDOM.unmountComponentAtNode(document.getElementById('root')) //旧版
        root.unmount()
    }
    return (
        <div>
            <p>count:{count}</p>
            <button onClick={add}>add</button>
            <button onClick={unmount}>unmount</button>
        </div>
    )
}


index.js 入口
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      {/* <App root={root}/>    */}
      <App/> 
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
export default root

可以把 useEffect Hook 看做如下三个函数的组合
component DidMount()
componentDidupdate()
componentwi 11Unmount()

P120 120尚硅谷react教程扩展5 RefHook

Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
语法:const refContainer = useRef()
作用:保存标签对象,功能与React.createRef()一样
专人专用

import React from 'react'
// import ReactDOM from 'react-dom'
import root from '../../index'

export default function Deme(props) {
    let [count,setCount]=React.useState(0)
    let myRef=React.useRef()
    // React.useEffect 相当生命周期
    React.useEffect(()=>{
        let timer=setInterval(()=>{
            setCount((count)=>count+1)
        },1000)
        return ()=>{
            //return 相当componentWillUnmount
            clearInterval(timer)
        }
    },[])//不写第二参数 全部检测 [count]检测count相当componentDidUpdate 写[]相当componentDidMount 
    let add=()=>{
        // setCount(count+props.num)
        setCount((preCount)=>count+props.num)
    }
    let unmount=()=>{
        // ReactDOM.unmountComponentAtNode(document.getElementById('root')) //旧版
        root.unmount()
    }
    let show=()=>{
        alert(myRef.current.value)
    }
    return (
        <div>
            <div><input type="text" ref={myRef}/></div>
            <p>count:{count}</p>
            <button onClick={add}>add</button>
            <button onClick={unmount}>unmount</button>
            <button onClick={show}>showInput</button>
        </div>
    )
}

P121 121_尚硅谷_react教程_扩展6_Fragment

Fragment

import React,{Fragment} from 'react'

export default function Deme() {
  return (
    // fragment 只能写key不能其他props
    <Fragment key={1}>
        <div>hello</div>
        {/* 标签同fragment效果 但是不能写key 任何 */}
        <>
            <span>react</span>
        </>
    </Fragment>
  )
}

P122 122_尚硅谷_react教程_扩展7_Context

5.Context理解
一种组件间通信方式,常用于【祖组件】与【后代组件】间通信

注意
在应用开发中一般不用context一般都用它的封装react插件 react-redux

import React, { Component } from 'react'
import './index.css'

let MyContext = React.createContext()
let { Provider,Consumer } = MyContext

export default class A extends Component {
    state = {
        name: 'koo',
        age: 28
    }
    render() {
        let { name, age } = this.state
        return (
            <div className='parent'>
                A组件
                <Provider value={{ name, age }}>
                    <B></B>
                </Provider>
            </div>
        )
    }
}
class B extends Component {
    render() {
        return (
            <div className='child'>
                B组件
                <C></C>
            </div>
        )
    }
}

//只能类组件使用
// class C extends Component {
//     static contextType=MyContext
//     render() {
//         let {name,age}=this.context
//         return (
//             <div className='grand'>
//                 C组件
//                 <del>{name}-{age}</del>
//             </div>
//         )
//     }
// }

// 函数和类组件使用
function C() {
    return (
        <div className='grand'>
            C组件
            <Consumer>
                {
                    value=><del>{value.name}-{value.age}</del>
                }
            </Consumer>
        </div>
    )
}

P123 123_尚硅谷_react教程_扩展8_PureComponent


Component的2个问题
1.只要执行setState(),即使不改变状态数据,组件也会重新render()2.只当前组件重新render(),就会自动重新render子组件 ==>效率低效率高的做法
只有当组件的state或props数据发生改变时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true解决

PureComponent pu-componet 重写shouldComponentUpdate 智能控制true 性能优化

import React, { Component,PureComponent } from 'react'

export default class Parent extends PureComponent {
    state={
        name:'koo',
        stus:['小李','小张']
    }
    // 用Component性能优化 用了PureComponent不用写 底层实现了
    // shouldComponentUpdate(nextProps,nextState){
    //     return !this.state.name===nextState.name
    // }
    addStu=()=>{
        // PureComponent 这样写不起作用  操作同一个堆地址 push unshift等方法
        let stus=this.state.stus
        let newStu='小刘'
        // stus.unshift(newStu)
        // this.setState({stus})
        this.setState({stus:[newStu,...stus]})
    }
    changeName=()=>{
        this.setState({name:'John'})

        //PureComponent 这样写不起作用  操作同一个
        // let obj=this.state
        // obj.name='john'
        // this.setState(obj)
    }
    render() {
        console.log('parent-render')
        let {name}=this.state
        return (
            <div>
                Parent:{name}
                <button onClick={this.changeName}>changeName</button>
                <br />
                {this.state.stus}
                <button onClick={this.addStu}>addStu</button>
                <Child name={name}></Child>    
            </div>
        )
    }
}
class Child extends PureComponent {
    // shouldComponentUpdate(nextProps,nextState){
    //     return !this.props.name===nextProps.name
    // }
    render() {
        console.log('child-render')
        return (
            <div>Child</div>
        )
    }
}

P124 124_尚硅谷_react教程_扩展9_renderProps

renderProps 相当vue 中的插槽

import React, { Component } from 'react'
import './index.css'


export default class A extends Component {
    render() {
        return (
            <div className='parent'>
                A组件
                {/* <B>
                    <C></C>
                </B> */}
                <B render={(name)=><C name={name}/>}></B>
            </div>
        )
    }
}
class B extends Component {
    state = {
        name: 'koo',
        age: 28
    }
    render() {
        let { name, age } = this.state
        return (
            <div className='child'>
                B组件
                {/* {this.props.children} */}
                {this.props.render(name)}
            </div>
        )
    }
}

//只能类组件使用
class C extends Component {
    render() {
        return (
            <div className='grand'>
                C组件
                {this.props.name}
            </div>
        )
    }
}


P125 125_尚硅谷_react教程_扩展10_ErrorBoundary

错误边界
理解:
错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面特点:
只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误

子组件出错 不向外扩 影响到组件 父组件做错误判断 用在生产环境的 开发环境用一会就继续error

当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息

componentDidCatch'统计错误此处,发送给后台');

import React, { Component } from 'react'
import Child from './Child'

export default class Parent extends Component {
    state={
        hasError:''
    }
    //用在生产环境的  开发环境用一会就继续error
    static getDerivedStateFromError(error){
        return {
            hasError:error
        }
    }
    componentDidCatch(){
        console.log('统计错误此处,发送给后台')
    }
    render() {
        return (
            <div>
                Parent
                {this.state.hasError?<h1>网络不稳定</h1>:<Child/>}
            </div>
        )
    }
}

import React, { Component } from 'react'

export default class Child extends Component {
    state ={
        // list:[
        //     {id:1,name:'koo'}
        // ]
        list:''
    }
        render() {
    return (
        <div>
            {
                this.state.list.map(item=>{
                    return <p key={item.id}>{item.name}</p>
                })
            }
        </div>
    )
}
}

P126 126_尚硅谷_react教程_组件间通信方式总结

9.组件通信方式总结
组件间的关系:
父子组件
兄弟组件(非嵌套组件)祖孙组件(跨级组件)几种通信方式:
1.props:
(1).children props
(2).render props
2.消息订阅-发布:
pubs-sub,event等等
3.集中式管理:
redux、dva等等
4.conText:生产者-消费者模式比较好的搭配方式:
父子组件:props兄弟组件:消息订阅-发布、集中式管理
祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)

P127 127_尚硅谷_ReactRouter6教程_课程说明

2021

1.React Router以三个不同的包发布到npm上,它们分别为:
1.react-router:路由的核心库,提供了很多的:组件、钩子。
2.react-router-dom:包含react-router所有内容,并添加一些专门用于 DoM 的组件,例如
3.react-router-native:包括react-router所有内容,并添加一些专门用于ReactNative的API,例如:等。
2.与React Router 5.x 版本相比,改变了什么?
1.内置组件的变化:移除 ,新增 等。
2.语法的变化:component={About}变为 element={}等。
3.新增多个hook:useParams、useNavigate、useMatch等。
4.官方明确推荐函数式组件了!!!

P128 128_尚硅谷_ReactRouter6教程_一级路由
npm i -S react-router-dom

同switch

import Home from './components/Home'
import Item from './components/Item'
import Loading from './components/Loading'
import { NavLink,Routes,Route } from 'react-router-dom';

function App() {
  return (
    <div>
      <NavLink to={'/home'}>home</NavLink>
      <NavLink to={'/item'}>item</NavLink>

      <Routes>
        <Route path='/home' element={<Home/>}></Route>
        <Route path='/item' element={<Item/>}></Route>
      </Routes>
    </div>
  );
}

export default App;

_P129 129_尚硅谷_ReactRouter6教程_重定向

navigate 只要挂载就切换

.属性用于指定:匹配时是否区分大小写(默认为false)。

import Home from './components/Home'
import Item from './components/Item'
import Loading from './components/Loading'
import { NavLink,Routes,Route,Navigate } from 'react-router-dom';

function App() {
  return (
    <div>
      <NavLink to={'/home'}>home</NavLink>
      <NavLink to={'/item'}>item</NavLink>

      <Routes>
        <Route path='/home' element={<Home/>}></Route>
        <Route path='/item' element={<Item/>}></Route>
        <Route path='/' element={<Navigate to={'/home'}/>}></Route>
      </Routes>
    </div>
  );
}

export default App;

import React,{useState} from 'react'
import { Navigate } from 'react-router-dom'

export default function Home() {
  let [num,setNum]=useState(0)
  let addNum=()=>{
    setNum(num=>num+1)
  }
  return (
    <div>
      <p>Home</p>
      {num===2?<Navigate to={'/item'} replace></Navigate>:<h1>{num}</h1>}
      <button onClick={addNum}>add</button>
    </div>
  )
}


P130 130-尚硅谷_ReactRouter6教程-NavLink高亮

import Home from './components/Home'
import Item from './components/Item'
import Loading from './components/Loading'
import { NavLink, Routes, Route, Navigate } from 'react-router-dom';

function App() {
  // 实现自定义高亮 active
  function computedClassName({ isActive }) {
    return isActive ? 'class1 class2' : ''
  }
  return (
    <div>
      <NavLink className={computedClassName} to={'/home'}>home</NavLink>
      <NavLink to={'/item'}>item</NavLink>

      <Routes>
        <Route path='/home' element={<Home />}></Route>
        <Route path='/item' element={<Item />}></Route>
        <Route path='/' element={<Navigate to={'/home'} />}></Route>
      </Routes>
    </div>
  );
}

export default App;

P131 131_尚硅谷_ReactRouter6教程_useRoutes路...

根据路由表生成对应的路由规则

src/routes/index.js
import Home from '../components/Home'
import Item from '../components/Item'
import { Navigate } from 'react-router-dom'

export default [
    {
        path:'/home',
        element:<Home/>
    },
    {
        path:'/item',
        element:<Item/>
    },
    {
        path:'/',
        element:<Navigate to={'/home'}/>
    }
]
import { NavLink,useRoutes } from 'react-router-dom';
import routes from './routes';

function App() {
  let element=useRoutes(routes)
  return (
    <div>
      <NavLink to={'/home'}>home</NavLink>
      <NavLink to={'/item'}>item</NavLink>

      {element}      
    </div>
  );
}

export default App;

P132 132_尚硅谷_ReactRouter6教程_嵌套路由

. ./ / navlink to写法

src/routes/index.jsx
import Home from '../components/Home'
import Item from '../components/Item'
import New from '../components/Item/New'
import Blog from '../components/Item/Blog'
import { Navigate } from 'react-router-dom'

export default [
    {
        path:'/home',
        element:<Home/>
    },
    {
        path:'/item',
        element:<Item/>,
        children:[
            {
                path:'new',
                element:<New/>
            },
            {
                path:'blog',
                element:<Blog/>
            },
            {
                path:'',
                element:<Navigate to={'blog'}/>
            }
        ]
    },
    {
        path:'/',
        element:<Navigate to={'/home'}/>
    }
]
App.js
import { NavLink,useRoutes } from 'react-router-dom';
import routes from './routes';

function App() {
  let element=useRoutes(routes)
  return (
    <div>
      <NavLink to={'/home'}>home</NavLink>
      <NavLink end to={'/item'}>item</NavLink>
      {/* end父级失去高亮 */}
      
      {element}      
    </div>
  );
}

export default App;

Item component
import React, { Component } from 'react'
import { NavLink,Outlet } from 'react-router-dom'

export default class Item extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><NavLink to={'new'}>new</NavLink></li>
          <li><NavLink to={'blog'}>blog</NavLink></li>
        </ul>
        {/* 相当vue的router-view */}
        <Outlet></Outlet>
      </div>
    )
  }
}

P133 133_尚硅谷_ReactRouter6教程_路由的param.

routes
import Home from '../components/Home'
import Item from '../components/Item'
import New from '../components/Item/New'
import Blog from '../components/Item/Blog'
import Detail from '../components/Item/Blog/Detail'
import { Navigate } from 'react-router-dom'

export default [
    {
        path:'/home',
        element:<Home/>
    },
    {
        path:'/item',
        element:<Item/>,
        children:[
            {
                path:'new',
                element:<New/>
            },
            {
                path:'blog',
                element:<Blog/>,
                children:[
                    {
                        path:'detail/:id/:name',
                        element:<Detail/>
                    },
                ]
            },
            {
                path:'',
                element:<Navigate to={'blog'}/>
            }
        ]
    },
    {
        path:'/',
        element:<Navigate to={'/home'}/>
    }
]
import React, { useState } from 'react'
import { Link,Outlet } from 'react-router-dom'

export default function Blog() {
  let [msg, setMsg] = useState([
    { id: 1, name: 'koo' },
    { id: 2, name: 'john' }
  ])
  return (
    <div>
        {
          msg.map(item=>{
            return (
              <div>
                <Link to={`detail/${item.id}/${item.name}`}>{item.name}</Link>
              </div>
            )
          })
        }
        <Outlet></Outlet>
    </div>
  )
}

import React from 'react'
import { useParams,useMatch } from 'react-router-dom'

export default function () {
  // 1.params
  let params=useParams()
  //useMatch少用
  // let match=useMatch('/item/blog/detail/:id/:name')
  // console.log(match).

  return (
    <div><del>{params.id}-{params.name}</del></div>
  )
}

P134 134_尚硅谷_ReactRouter6教程_路由的search..

{
                path:'blog',
                element:<Blog/>,
                children:[
                    {
                        path:'detail',
                        element:<Detail/>
                    },
                ]
            },
import React, { useState } from 'react'
import { Link,Outlet } from 'react-router-dom'

export default function Blog() {
  let [msg, setMsg] = useState([
    { id: 1, name: 'koo' },
    { id: 2, name: 'john' }
  ])
  return (
    <div>
        {
          msg.map(item=>{
            return (
              <div>
                <Link to={`detail?id=${item.id}&name=${item.name}`}>{item.name}</Link>
              </div>
            )
          })
        }
        <Outlet></Outlet>
    </div>
  )
}

import React from 'react'
import { useSearchParams,useLocation } from 'react-router-dom'

export default function () {
  // search
  let [search,setSearch]=useSearchParams()
  let id=search.get('id')
  let name=search.get('name')
  console.log(useLocation())
  let change=()=>{
    setSearch('id=8&name=hello')
  }
  return (
    <div>
      <del>{id}-{name}</del>
      <button onClick={change}>change</button>
    </div>
  )
}

P135 135_尚硅谷_ReactRouter6教程_路由的state.

import React, { useState } from 'react'
import { Link,Outlet } from 'react-router-dom'

export default function Blog() {
  let [msg, setMsg] = useState([
    { id: 1, name: 'koo' },
    { id: 2, name: 'john' }
  ])
  return (
    <div>
        {
          msg.map(item=>{
            return (
              <div>
                <Link to={`detail`} state={{id:item.id,name:item.name}}>{item.name}</Link>
              </div>
            )
          })
        }
        <Outlet></Outlet>
    </div>
  )
}

import React from 'react'
import { useLocation } from 'react-router-dom'

export default function () {
  // state
  let {state:{id,name}}=useLocation()
  return (
    <div>
      <del>{id}-{name}</del>
    </div>
  )
}

P136 136_尚硅谷_ReactRouter6教程-编程式路由导航

import React, { useState } from 'react'
import { Link,Outlet,useNavigate } from 'react-router-dom'

export default function Blog() {
  let navigate=useNavigate()
  let [msg, setMsg] = useState([
    { id: 1, name: 'koo' },
    { id: 2, name: 'john' }
  ])
  let go=()=>{
    // navigate(-1) //前进1 -1 后退1
    // navigate('detail?id=1&name=kk')
    // navigate('detail/1/kk')
    navigate('detail',{
      replace:false,
      state:{
        id:8,
        name:'hello react'
      }
    })
    
  }
  return (
    <div>
        {
          msg.map(item=>{
            return (
              <div key={item.id}>
                <Link to={`detail`} state={{id:item.id,name:item.name}}>{item.name}</Link>
                <button onClick={go}>go</button>
              </div>
            )
          })
        }
        <Outlet></Outlet>
    </div>
  )
}

P137 137-尚硅谷_ReactRouter6教程_uselnRouter...

import { NavLink,useRoutes,useInRouterContext } from 'react-router-dom';
import routes from './routes';

function App() {
  let element=useRoutes(routes)
  console.log(useInRouterContext()) //<BrowserRouter>路由器包裹的都为true
  return (
    <div>
      <NavLink to={'/home'}>home</NavLink>
      <NavLink end to={'/item'}>item</NavLink>
      {/* end父级失去高亮 */}
      
      {element}      
    </div>
  );
}

export default App;

P138 138_尚硅谷_ReactRouter6教程_useNavigatio...

8.useNavigationType()
1.作用:返回当前的导航类型(用户是如何来到当前页面的)。
2.返回值:POP、PUSH、REPLACE。
3.备注:POP 是指在浏览器中直接打开了这个路由组件(刷新页面)。

import React from 'react'
import { useNavigationType } from 'react-router-dom'

export default function New() {
  console.log(useNavigationType()) //默认push跳转 pop刷新 replace替换
  return (
    <div>New</div>
  )
}

P139 139_尚硅谷_ReactRouter6教程_useOutlet

9.useOutlet()
1.作用:用来呈现当前组件中渲染的嵌套路由。

如果嵌套路由没有挂载,则result为null
,如果嵌套路由已经挂载,则展示嵌套的路由对象

import { NavLink,Outlet,useOutlet} from 'react-router-dom'
import React from 'react'

export default function Item() {
  console.log(useOutlet(),'outlet') //挂载 输出组件路由对象 在outlet组件用
  return (
    <div>
      <ul>
        <li><NavLink to={'new'}>new</NavLink></li>
        <li><NavLink to={'blog'}>blog</NavLink></li>
      </ul>
      {/* 相当vue的router-view */}
      <Outlet></Outlet>
    </div>
  )
}


P140 140-尚硅谷_ReactRouter6教程_useOutletuse..

import React from 'react'
import { useNavigationType,useResolvedPath } from 'react-router-dom'

export default function New() {
  console.log(useNavigationType()) //默认push跳转 pop刷新 replace替换
  console.log(useResolvedPath('user?id=1&name=hello#get')) //解析路径的
  return (
    <div>New</div>
  )
}

P141 141_尚硅谷_ReactRouter6教程-总结

image
image
image
image
image
image

posted @ 2024-12-14 13:21  KooTeam  阅读(153)  评论(0)    收藏  举报