react随手记

目录

组件间的通信方式

配置代理

React-router-dom

Switch,Redirect

传递接收params,search,state参数,goBack(),goForward()

withRouter

redux+react-redux:用于多个组件间状态共享

setState的函数写法与对象写法

lazy:实现路由懒加载、Suspense

函数式组件

useState、useEffect、useRef

Fragment

Context

PureComponent

render_props

错误边界

Fetch

创建脚手架命令:

create-react-app 项目名

组件间的通信方式

组件通信方式:
1.父子间通信:
父组件:
<child abc={xxx}/>
子组件:
props.abc拿到数据
2.兄弟间通信:

(1)消息订阅与发布,redux集中式管理

(2)找到共同的父亲,然后将数据放在父亲身上,再通过子传父和父传子的方式来获取数据
3.

(1)消息订阅与发布,redux集中式管理

(2)祖孙通信Context:const {Provider,Consumer} = React.createContext()
祖先组件:
<Provider value={xxx}>
</Provider>
孙子组件:
<Consumer>
    (value)=>{
        return()}
</Consumer>


props校验:
安装prop-type包,然后引入在要用的组件中import PropTypes from 'prop-type'
例如:App组件中的Porps校验
App.propTypes={
    colors:PropTypes.array
    fn:PropTypes.func.isRequired//表示传过来的是一个函数,并且是必传项
}

//添加props默认值
App.defaultProps = {
    pageSize: 10//当其他组件没有传pageSize值给App时,默认接收的是10
}

Router6:useNavigationType, useResolvedPath

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

export default function Demo() {
 /*  作用:返回当前的导航类型(用户是如何来到当前页面的)
    返回值:POP、PUSH、RESPLACE
    备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面) */
  console.log(useNavigationType())

  // 作用:给定一个URL值,解析其中的:path、search、hash值
  console.log(useResolvedPath('/user?id=001&name=tom#qwe'))
  // {pathname: '/user', search: '?id=001&name=tom', hash: '#qwe'}
  return (
    <div>Demo</div>
  )
}

Router6:<Outlet/>

<Outlet/>:当<Route>与useRoutes()一起使用配置‘路由表‘,则需要<Outlet>来渲染子路由

Router6:params,search,state路由传参,编程式路由导航navigate,navigate前进与后退

//在routes.js组件中:
import { lazy } from "react";
import { Navigate } from "react-router-dom";
// const Home = lazy(()=>import('./pages/Home'))
// const About = lazy(()=>import('./pages/About'))
import Home from './pages/Home'
import About from './pages/About'
import Message from './pages/Message'
import News from './pages/News'
import Msgdetail from './pages/Msgdetail'
import Newsdetail from './pages/Newsdetail'

export default [
  // 路由重定向
  {
    path:'/',
    element:<Navigate to='/about'/>
  },
  {
    path:'/about',
    element:<About/>
  },
  {
    path:'/home',
    element:<Home/>,
    children:[
      {
        path:'message',
        element:<Message/>,
        children:[
          {
            path:'detail',
            element:<Msgdetail/>
          }
        ]
      },
      {
        path:'news',
        element:<News/>,
        children:[
          {
            path:'detail',
            element:<Newsdetail/>
          }
        ]
      }
    ]
  }
]


//在MyNavLink组件中:
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'

export default class MyNavLink extends Component {
  render() {
    // console.log(this.props)
    return (
      <div>
        <NavLink {...this.props}></NavLink>
      </div>
    )
  }
}

//App.js组件中:
import react from 'react'
import { Link ,Route ,NavLink,useRoutes} from 'react-router-dom'
import './pages/App.css'
import MyNavLink from './components/MyNavLink'
import Header from './components/Header'
import routes from './routes'

function App(){
    const element = useRoutes(routes)
        return (
            <div>
                <Header/>
                <hr/>
                <div className='route_show'>
                <ul >
                {/* <Link to='/home'>home</Link>
                <Link to='/about'>about</Link> */}
                    {/* <NavLink to='/home'>home</NavLink>
                    <NavLink to='/about'>about</NavLink> */}

                    
                    {/* 对NavLink进行二次封装 */}
                    <MyNavLink to="/about">about</MyNavLink>
                    <MyNavLink to="/home">home</MyNavLink>
                </ul>
                <div className='content_right'>
                    {element}
                </div>
            </div>
            </div>
        )
    }

export default App


//在Home组件中:
import React, { Component } from 'react'
import MyNavLink from '../components/MyNavLink'
import { Route ,Routes,Outlet} from 'react-router-dom'
// import Message from './Message'
// import News from './News'

export default class Home extends Component {
  render() {
    return (
      <div>
        <li>我是Home组件</li>
        <ol>
          <li>
            <MyNavLink to="news">News</MyNavLink>
            <MyNavLink to="message">Message</MyNavLink>
          </li>
          <hr />
          {/* <Switch className="route">
            <Route path="/home/news" component={News}></Route>
            <Route path="/home/message" component={Message}></Route>
          </Switch> */}
          {/* <Routes className="route">
            <Route path="/home/news" element={<News/>}></Route>
            <Route path="/home/message" element={<Message/>}></Route>
          </Routes> */}
          <Outlet/>
        </ol>
      </div>
    )
  }
}


//在Message组件中:

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

export default function Message() {
  const navigate = useNavigate()
  const [state, setState] = useState([
    { id: 1, title: 'msg1', content: 'love china' },
    { id: 2, title: 'msg2', content: 'love jx' },
    { id: 3, title: 'msg3', content: 'love sr' },
  ])
  function showMsgdetail(v) {
    navigate('detail', {
      // 编程式路由导航只能传递state参数,params和search参数是直接写在要跳转的链接或者路由后面进行拼接
      replace: false,
      state: {
        id: v.id,
        title: v.title
      }
    })
  }
  return (
    <div>
      <ul>
        {
          state.map(v => {
            return (
              <li key={v.id}>
                {/* 传递prarms参数 */}
                {/* <Link to={`/home/message/detail/${v.id}/${v.title}`}>{v.title}</Link> */}
                {/* 传递search(query)参数 */}
                {/* <Link to={`/home/message/detail?id=${v.id}&title=${v.title}`}>{v.title}</Link> */}
                {/* 传递state参数 */}
                {/* <Link to='detail' state={{id:v.id,title:v.title}}>{v.title}</Link> */}
                <button onClick={() => showMsgdetail(v)}>点击传递state参数跳转到msgdetail页面(编程式路由push)</button>
              </li>
            )
          })
        }
        <Outlet />
      </ul>
    </div>
  )
}


//在MsgDetail组件中:

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

const data = [
  {id:1,content:'love china'},
  {id:2,content:'love jx'},
  {id:3,content:'love sr'},
]
export default function Msgdetail(){
  // 接收params参数
    /* const param = useParams()
    const {id,title} = param */

    // 接收search参数,修改search参数的方法
    /* const [search,setSearch] = useSearchParams()
    const id = search.get('id')
    const title = search.get('title') */

    // 接收state参数
    const {state:{id,title}} = useLocation()
    let resultContent = data.find(v=>{
      return v.id==id
    })||{}
    return (
      <p>
        <li>{id}</li>
        <li>{title}</li>
        <li>{resultContent.content}</li>
        {/* setSearch:改变search参数的方法 */}
        {/* <button onClick={()=>setSearch("id='7'&title='hhh'")}>点击改变search参数</button> */}
      </p>
    )
  }


//在Header非路由组件中实现前进与后退:
import React, { Component } from 'react'
import { useNavigate } from 'react-router-dom'

function Header() {
  const navigate = useNavigate()
  function goBack(){
    // router5
    // this.props.history.goBack()
    
    // router6
    navigate(-1)
  }
  function goForward(){
    // this.props.history.goForward()
    navigate(1)
  }
    return (
      <div className='react_header'>
        <h2>React-router-dom</h2>
        <button onClick={goBack}>回退</button>&nbsp;
        <button onClick={goForward}>前进</button>
      </div>
    )
  }

export default Header

Router6hook:useResolvedPath()

//作用:给定一个URL值,解析其中的path、search、hash值

Router6:Navigate,element,Routes,NavLink自定义高亮显示

//在App.js组件中:
import React, { Component } from 'react'
import { NavLink, Routes, Route, Navigate ,useRoutes} from 'react-router-dom'
import Fun from './Navigate'
import Error from './Error'

function App(){
  function computeClassName({isActive}){
    return  isActive ? 'linkFont activeLink' : 'linkFont'
  }
    return (
      <div>
//className:接收一个函数
        <NavLink className={computeClassName} to='/navigate'>navigate</NavLink>&nbsp;&nbsp;&nbsp;
        <NavLink className={computeClassName} to='/error'>error</NavLink>
        <div>
          <Routes>
            <Route path='/navigate' element={<Fun />} />
            <Route path='/error' element={<Error />} />
            <Route path='/' element={<Navigate to='/error' />} />
          </Routes>
        </div>
      </div>
    )
  }

  export default App



//在Navigate组件中:
import React, { useState } from 'react'
import { Navigate } from 'react-router-dom'

export default function Nav() {
  const [sum,setSum] = useState(1)
  return (
    <div>
      {/* 重定向Navigate:指定跳转到指定页面 */}
      {sum==2?<Navigate to='/error'/>:<h2>sum:{sum}</h2>}
      <button onClick={()=>setSum(2)}>点击sum变为2</button>
      
    </div>
  )
}





Router6:路由表

//在src下新建routes.js:
import { lazy } from "react";
import { Navigate } from "react-router-dom";

// const Nav = lazy(()=>import('./Navigate'))
// const Error = lazy(()=>import('./Error'))
import Nav from "./Navigate";
import Error from './Error'

export default [
  {
    path:'/navigate',
    element:<Nav/>
  },
  {
    path:'/error',
    element:<Error/>
  },
  {
    path:'/',
    element:<Navigate to='/navigate'/>
  }
]

//在App.js组件中:
import React, { Component } from 'react'
import { NavLink,useRoutes} from 'react-router-dom'
import routes from './routes'

function App(){
  const element = useRoutes(routes)
    return (
      <div>
        <NavLink to='/navigate'>navigate</NavLink>&nbsp;&nbsp;&nbsp;
        <NavLink to='/error'>error</NavLink>
        <div>
          {element}
        </div>
      </div>
    )
  }

  export default App

useCallback

 // 防止因为组件重新渲染,导致方法被重新创建,起到缓存作用,只有第二个参数变化,才重新声明渲染
  const Fun = useCallback(()=>{
        // 函数
        ()=>{}
    },[name])

useMemo

const a = useMemo(()=>{
        // 函数
        ()=>{}
    },[name])
//与Vue中的compute属性类似,a得到的结果是useMemo第一个函数参数的返回值,第二个参数是监测改变的数据
//如果数组中的name没有发生变化,则函数会采取缓存的方式,return回上次的返回值

配置代理

在src/setupProxy.js中:

const proxy = require('http-proxy-middleware')


module.exports = function(app){

  app.use(

    proxy('/api',{

      target:'http://localhost:5000',

      changeOrigin:true,

      pathRewrite:{'^/api':""}

    })

  )

}

React-router-dom

//在src/index.js中
import {BrowserRouter} from 'react-router-dom'
//import {HashRouter} from 'react-router-dom':可以解决刷新页面后样式丢失问题#后面默认为是前端资源,不带给服务器
ReactDOM.render(
  <BrowserRouter>
      <App/>
  </BrowserRouter>,
  document.getElementById('root')
)

//在组件中
import {Link ,Route} from 'react-router-dom' 
//路由链接  
 //<Link className="item" to="/about">路由跳转</Link>
//NavLink中有一个属性activeName:点击跳转到哪个路由哪个标签高亮
<NavLink activeName="abc" className="item" to="/about">路由跳转到about</Link>
<NavLink activeName="abc" className="item" to="/home">路由跳转home</Link>
//注册路由
<Route path="/about" component={About}/>
//在App.js组件中:
import react from 'react'
import { Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import MyNavLink from './components/MyNavLink'

class App extends react.Component {
    render() {
        return (
            <div className='route_show'>
                <ul >
                    {/* <NavLink to='/home'>home</NavLink>
                    <NavLink to='/about'>about</NavLink> */}

                    
                    {/* 对NavLink进行二次封装 */}
                    <MyNavLink to="/about">about</MyNavLink>
                    <MyNavLink to="/home">home</MyNavLink>
//在MyNavLink中通过this.props.children可以获取该标签体中的内容,而无需与vue一样使用插槽
                </ul>
                <div className='content_right'>
                        //exact:开启精准匹配
                    <Route path='/about' exact component={About}></Route>
                    <Route path='/home' component={Home}></Route>
                </div>
            </div>
        )
    }
}

export default App


//在MynavLink组件中:

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

export default class MyNavLink extends Component {
  render() {
    console.log(this.props)
    return (
      <div>
        <NavLink activeClassName='active' {...this.props}></NavLink>
      </div>
    )
  }
}

Router5:

Switch,Redirect

//在router5中使用Switch和component配合:用于提高代效率,使得path与对应component匹配到之后就不再往下继续匹配
//在router6中使用Routes和element配合

import { Route ,Switch ,Routes ,Redirect ,Navigate} from 'react-router-dom'
/*<Switch>
    <Route path='/about' component={About}></Route>
    <Route path='/home' component={Home}></Route>
//router5中重定向路由,默认页面一开始就展示about页面
    <Redirect to="about"/>
</Switch>*/


 <Routes className="route">
//caseSensitive :指定path匹配时是否区分大小,写默认为false
    <Route caseSensitive path="/home/news" element={<News/>}></Route>
    <Route path="/home/message" element={<Message/>}></Route>
    //router6重定向方式:
    <Route path='/' element={<Navigate to='/about'/>></Route>
 </Routes>

传递接收params,search,state参数,goBack(),goForward()

//在message组件中:
// 传递params参数

// 传递params参数

import React, { Component } from 'react'
import { Route ,Link} from 'react-router-dom'
import Msgdetail from './Msgdetail'

export default class Message extends Component {
  state = {
    messageList:[
      {id:1,title:'msg1',content:'love china'},
      {id:2,title:'msg2',content:'love jx'},
      {id:3,title:'msg3',content:'love sr'},
    ]
  }
//用push进行路由跳转
   pushShow = (id,title)=>{
    // 接收state参数进行路由跳转
    this.props.history.push('/home/message/detail',{id:id,title:title})
    //this.props.history.goBack()//回退
  }
    replaceShow = (id,title)=>{
    // 接收state参数进行路由跳转
    this.props.history.replace('/home/message/detail',{id:id,title:title})
    //this.props.history.goForward()//前进
  }
  render() {
    return (
      <div>
        <ul>
          {
            this.state.messageList.map(v=>{
              return (
                <li key={v.id}>
                  {/* 传递prarms参数 */}
                  {/* <Link to={`/home/message/detail/${v.id}/${v.title}`}>{v.title}</Link> */}
                  {/* 传递search(query)参数 */}
                  {/* <Link to={`/home/message/detail?id=${v.id}&title=${v.title}`}>{v.title}</Link> */}
                  {/* 传递state参数   replace:消除历史痕迹*/}
                  <Link replace to={{pathname:'/home/message/detail',state:{id:v.id,title:v.title}}}>{v.title}</Link>
                  <button onClick={this.pushShow(v.id,v.title)}>编程式路由有历史缓存push</button>
                  <button onClick={this.replaceShow(v.id,v.title)}>编程式路由无历史缓存replace</button>
                </li>
              )
            })
          }
          {/* 声明接受query参数 */}
          {/* <Route path="/home/message/detail/:id/:title" component={Msgdetail}/> */}
          {/* 接收search,state参数,都无需声明 */}
          <Route path="/home/message/detail" component={Msgdetail}/>
        </ul>
      </div>
    )
  }
}


//在Msgdetail中:

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

const data = [
  {id:1,content:'love china'},
  {id:2,content:'love jx'},
  {id:3,content:'love sr'},
]
export default class Msgdetail extends Component {
  render() {
    // console.log(this.props)
    //接收params参数
    // const {id,title} = this.props.match.params

    //接收search参数
    // id=1&title=msg1:是urlencode的编码形式
    /* const {search} =this.props.location
    let searchquery = qs.parse(search.slice(1))
    const {id,title} =searchquery */

    // 接收state参数:导航栏中不显示传递的参数
    const {id,title} =this.props.location.state||{}
   console.log(this.props.location)
    let resultContent = data.find(v=>{
      return v.id==id
    })||{}
    return (
      <p>
        <li>{id}</li>
        <li>{title}</li>
        <li>{resultContent.content}</li>
      </p>
    )
  }
}

withRouter

//在非路由组件中:
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'

class Header extends Component {
  goBack = ()=>{
    this.props.history.goBack()
  }
  goForward = ()=>{
    this.props.history.goForward()
  }
  render() {
    return (
      <div className='react_header'>
        <h2>React-router-dom</h2>
        <button onClick={this.goBack}>回退</button>&nbsp;
        <button onClick={this.goForward}>前进</button>
      </div>
    )
  }
}

//widthRouter:加工非路由组件,让非路由组件也具有路由组件中的Api(如:this.props中的值),widthRouter的返回值是一个新组件
export default withRouter(Header)

redux+react-redux:用于多个组件间状态共享

//在index.js入口文件中:
import React from 'react'//JSX语法需要
import  {createRoot}  from 'react-dom/client'//可以帮我们把React组件渲染到页面上去
import { Provider } from 'react-redux'
import App from './App'
import store from './redux/store'

const container = document.getElementById('root')
const root = createRoot(container)
root.render(
    // 将store传给每一个容器组件
    <Provider store={store}>
        <App/>
    </Provider>
    
)
// 获取到redux中的数据后即使更新组件(如果使用了react-redux第三方库,则无需subscribe监测组件状态的变化
/* store.subscribe(()=>{
    root.render(
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    )
}) */


//在App.js组件中:
import React, { Component } from 'react'
// 引入的是count组件的父容器
import Count from './containers/Count'
import Person from './containers/Person'
// 统一在index.js中使用react-redux第三方库提供的Provider组件来将store传给每一个容器组件
// import store from './redux/store'

export default class App extends Component {
  render() {
    return (
      // <div><Count store={store}/></div>
      <div>
        <Count/>
         <hr/>
        <Person/>
      </div>
    )
  }
}
//在redux/store.js中:
import { createStore ,applyMiddleware} from "redux";
// 使得异步action接收函数为返回值可以被store允许
import thunk from "redux-thunk";
import reducers from './reducers'

export default createStore(reducers,applyMiddleware(thunk))


//在redux/reducers/index.js中:

import { combineReducers} from "redux";
import countRedux from './count'
import personRedux from "./person";

export default combineReducers({count:countRedux,person:personRedux})


//在redux/reducers/count.js中:

const initState = 0
export default function (preState = initState, action) {
  const { type, data } = action
  switch (type) {
    case 'increment':
      return preState + data
    case 'decrement':
      return preState - data
    default :
      return preState
  }
}

//在redux/reducers/person.js组件中:
import { ADD_PERSON } from "../constant"
const initState = [{id:'001',name:'tom',age:19}]

export default function(preState=initState,action){
  const {type,data} = action
  switch(type){
    case ADD_PERSON:
      return [data,...preState]
    default:
      return preState
  }
}

//在redux/constant.js中:

// 定义常量:便于管理
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON ='add_person'


//在redux/actions/count.js中:

import { INCREMENT,DECREMENT } from "./constant";
export const createIncrementAction = data => ({type:INCREMENT,data})
// 如果action的返回值为一个对象,则为同步action
export const createDecrementAction = data => ({type:DECREMENT,data})

export const createIncrementAsyncAction = (data,time)=>{
  // 由store调用,传入dispatch参数
  // 如果action的返回值为一个函数,则为异步action
  return (dispatch)=>{
    setTimeout(()=>{
      dispatch(createIncrementAction(data))
    },time)
  }
}


//在redux/actions/person.js中:
import {ADD_PERSON} from '../constant'

export const addPerson = personObj=>({type:ADD_PERSON,data:personObj})
//在constiner/Count.js组件中:

import { connect } from "react-redux";
import { createIncrementAction,createDecrementAction,createIncrementAsyncAction } from '../redux/count_actions'

import React, { Component, createRef } from 'react'
// import store from '../redux/store'

class Count extends Component {
  state = {count:0}
  componentDidMount(){
    console.log(this.props,'count-------------')
  }
  increment = ()=>{
    const {value} = this.myRef
    this.props.createIncrementAction(value*1)
  }
  decrement = ()=>{
    const {value} = this.myRef
    this.props.createDecrementAction(value*1)
  }
  incrementOdd = ()=>{
    const {value} = this.myRef
    const count = this.props.count
    if(count%2!==0){
      // store.dispatch(createIncrementAction(value*1))
      // 借用react-redux第三方库为中间人
      this.props.createIncrementAsyncAction(value*1)
    }
  }
  incrementAsync = ()=>{
    const {value} = this.myRef
    this.props.jiaAsync(value*1,500)
  }
  render() {
    const {count,personNumber} =this.state
    return (
      <div>
                <h1>Count的值为:{this.props.count},person组件有{this.props.personNumber}人</h1>
        <select name="" id="" ref={v=>this.myRef=v}>
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={3}>3</option>
        </select>&nbsp;
        <button onClick={this.increment}>+</button>&nbsp;
        <button onClick={this.decrement}>-</button>&nbsp;
        <button onClick={this.incrementOdd}>奇数+</button>&nbsp;
        <button onClick={this.incrementAsync}>异步+</button>&nbsp;
      </div>
    )
  }
}



// 接收count组件的状态,返回值是一个对象
/* const mapStateToProps = (state)=>{
  return {count:state}
} */
// 接收count组件的方法,返回值是一个对象
// mapActionToProps一般写法
/* const mapActionToProps = (dispatch)=>{
  return {
    jia:(number)=>{dispatch(createIncrementAction(number)) },
    jian:(number)=>{dispatch(createDecrementAction(number))},
    jiaAsync:(number,time)=>{
      setTimeout(()=>{
        dispatch(createIncrementAsyncAction(number))
      },time)
    }
  }
} */
export default connect(
  state=>({
      count:state.count,
      personNumber:state.person.length
   }),
  // mapActionToProps简化版
  // 第二个参数可以接收一个function,也可以接收一个对象
  {
    createIncrementAction,//react-redux默认会帮忙调用dispatch
    createDecrementAction,
    createIncrementAsyncAction
  }
  )(Count)


//在contsiners/Person.js组件中:
import React, { Component } from 'react'
import {addPerson} from '../redux/actions/person'
import { connect } from 'react-redux'

class Person extends Component {
  addPerson = ()=>{
    let {value:name} = this.nameRef
    let {value:age} = this.ageRef
    // console.log(name,age)
    let personObj = {id:Math.random()*99999,name,age}
    this.props.addPerson(personObj)
    // console.log(this.props)
    this.nameRef.value=''
    this.ageRef.value=''
  }
  render() {
    const {person,count} = this.props
    // console.log(this.props)
    return (
      <div>
        <input type="text" placeholder='请输入名字' ref={v=>this.nameRef=v}/>&nbsp;
        <input type="text" placeholder='请输入年龄' ref={v=>this.ageRef=v}/>&nbsp;
        <button onClick={this.addPerson}>添加</button><br/>
        <div>count组件求和为{count}</div>
        <ul>
          {
            person.map(p=>{
              return (<li key={p.id}><span>{p.name}</span>:<span>{p.age}</span></li>)
            })
          }
        </ul>
      </div>
    )
  }
}

export default connect(
  state=>(
    {person:state.person,
    count:state.count}
  ),
  {
    addPerson
  }
)(Person)

setState的函数写法与对象写法

import React, { Component } from 'react'

export default class Count extends Component {
  state = {
    count:0
  }
  add = ()=>{
    // this.setState对象写法
    /* this.setState({count:this.state.count+1},()=>{
      console.log(this.state.count,'对象写法回调函数------')//1
    }) */

    // this.setState函数写法
    this.setState((state,props)=>{
      return ({count:state.count+1})
    },()=>{
      console.log(this.state.count,'函数写法回调函数------')
    })
    // console.log(this.state.count):0
  }
  // setState异步更新状态,接收两个参数({},()=>{}):()=>{}:在setState异步更新状态结束后,并且render调用后执行
  render() {
    return (
      <div>
        <div>Count的值为:{this.state.count}</div>
        <button onClick={this.add}>点击+1</button>
      </div>
    )
  }
}

lazy:实现路由懒加载、Suspense

import React,{Component,lazy,Suspense} from 'react'
import { Link ,Route ,Redirect} from 'react-router-dom'
import Header from './components/Header'
import './App.css'
// import About from './pages/About'
// import Home from './pages/Home'
// 路由懒加载:按需加载
const Home = lazy(()=>import ('./pages/Home'))
const About = lazy(()=>import ('./pages/About'))


class App extends Component {
    render() {
        return (
            <div>
                <Header/>
                <hr/>
                <div className='route_show'>
                <ul >
                <Link to='/home'>home</Link>
                <Link to='/about'>about</Link>
                </ul>
                <div className='content_right'>
                  {/* Suspense:用于指定页面出错加载不出来时而展示给用户看的页面 ,fallback:接收一个组件*/}
                  <Suspense fallback={<h1>loading...</h1>}>
                    <Route path='/about' component={About}></Route>
                    <Route path='/home' component={Home}></Route>
                    <Redirect to="/about"/>
                  </Suspense>
                   
                </div>
            </div>
            </div>
        )
    }
}

export default App

函数式组件

useState、useEffect、useRef

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

/* export default class FunUse extends Component {
  state = {count:0}
  componentDidMount(){
    this.timer = setInterval(()=>{
      this.setState({count:this.state.count+1})
    },500)
  }
  increment = ()=>{
    this.setState(state=>({count:state.count+1}))
  }
  componentWillUnmount(){
    clearInterval(this.timer)
  }
  unMount = ()=>{
    // 卸载组件
    root.unmount()
  }
  render() {
    return (
      <div>
        <h2>Count的值为:{this.state.count}</h2>
        <button onClick={this.increment}>点击+1</button>
        <button onClick={this.unMount}>点击卸载组件</button>
      </div>
    )
  }
} */
export default function FunUse(){
  const [count,setCount] = React.useState(0)
  const myRef = React.useRef()
  /* 
    React.useEffect(()=>{},[]):
    第二个参数为[]时=componentDidMount,不写第二个参数时=componentDidUpdated
    第二个参数为[count]:表示只监测count状态的改变,只有count状态改变才会重新调用useEffect,
    useEffect()的第一个参数接收一个函数作为返回值,该返回值的函数 = componentWillUnmount
  */
  React.useEffect(()=>{
   let timer = setInterval(()=>{
    // 在useEffect中使用定时器时只能使用函数的更新方式
    setCount(count=>count+1)
   },1000)
   return ()=>{
    clearInterval(timer)
    console.log('即将卸载组件')
   }
  },[])
  const increment = ()=>{
    // 第一种写法
    setCount(count+1)
    // setCount(value=>newValue):第二种写法
    // setCount(count=>count+1)
  }
  const unMount = ()=>{
    console.log('卸载组件')
    root.unmount()
  }
  const getData = ()=>{
    console.log(myRef.current.value)
  }
  return (
    <div>
      <input type="text" ref={myRef}/>&nbsp;
      <button onClick={getData}>点击获取input框中的值(useRef)</button>
      <h2>Count的值为:{count}</h2>
      <button onClick={increment}>点击+1(useState)</button>&nbsp;
      <button onClick={unMount}>点击卸载组件(useEffect)</button>&nbsp;
    </div>
  )
}

Fragment

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

export default class Fragment extends Component {
  render() {
    return (
      <Fragment>
        {/* 作为根标签,不会渲染到页面上 */}
      </Fragment>
    )
  }
}

Context

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

// 创建Context容器对象
const MyContext = React.createContext()
const {Provider} = MyContext
export default class One extends Component {
  state = {name:'jack'}
  render() {
    return (
      <Fragment>
        {/* 传入想要给后代的值value */}
        <Provider value={this.state.name}>
          <Two/>
        </Provider>
      </Fragment>
    )
  }
}


class Two extends Component {
  render() {
    return (
      <div>
        <Three/>
      </div>
    )
  }
}

function Three(){
  return (
    <MyContext.Consumer>
      {
        // 用一个函数接收从祖先传过来的值,该函数的参数就是祖先传过来的value
        val=><span>从祖先接收过来的值:{val}</span>
      }
    </MyContext.Consumer>
  )
}

PureComponent

import React, {   PureComponent } from 'react'

/* 
  PureComponent与Component的:
  Component的2个问题:
    1.只要执行setState(),即使不改变状态数据,组件也会重新render()
    2.只要当前组件重新render(),即使子组件没有接收任何父组件的数据,
    也会自从重新render子组件==>效率低
  PureComponent:
    底层重写了shoudComponentUpdate(),只有state或props数据有变化时才返回true
    注意:只是进行state与props数据的浅比较,如果只是数据对象内部数据变化了,
    则shoudComponentUpdate()会返回false,不更新页面
*/

export default class PureComponent extends PureComponent {
  render() {
    return (
      <div>PureComponent</div>
    )
  }
}

render_props

import React, { Component } from 'react'

export default class Slot extends Component {
  render() {
    return (
      <div>
        <B render={name=><C name={name}/>}></B>
        {/* <B>
          <C/>
        </B> */}
      </div>
    )
  }
}

class B extends Component {
  // B组件将name传给C组件
  state = {name:'jack'}
  render() {
    const {name} = this.state
    // 拿到B组件在Slot组件中的标签体内容
    // console.log(this.props.children)
    return (
      <div>
        {/* 调用父组件中传过来的render函数 */}
        B:{this.props.render(name)}
      </div>
    )
  }
}

class C extends Component {
  render() {
    return (
      <div>接收从父组件B中传来的name:{this.props.name}</div>
    )
  }
}

错误边界

import React, { Component } from 'react'

export default class Parent extends Component {
  state = {
    hasError: ''
  }
  // 生命周期函数,当parent的子组件出现报错时,会触发getDerivedStateFromError调用,并携带错误信息
  static getDerivedStateFromError(error) {
    return { hasError: error }
  }
  componentDidCatch(){
    console.log('此处常用于统计错误次数法,反馈给服务器,通知程序员修改')
  }
  render() {
    return (
      <div>
        <p>Parent组件</p>
        {this.state.hasError ? <h2>当前网络不稳定,请稍后再试</h2> : <Child />}
        <div>子组件即使报错也能正常渲染</div>
      </div>
    )
  }
}

class Child extends Component {
  state = {
    // 数据错误,本来是数组但是写出字符串使得遍历people的时候报错,
    // 则需要用错误边界在父组件中进行拦截错误,使得页面正常渲染
    people: ''
  }
  render() {
    return (
      <div>
        {
          this.state.people.map(v => {
            return <li key={v.id}>v</li>
          })
        }
      </div>
    )
  }
}

Fetch

//使用fetch发送网络请求(浏览器自带)

//不简化写法

 fetch(url)
  .then(
    response=>{//该response拿到的是请求的状态
      console.log('联系服务器成功了')
      return response.json()//返回一个promise的对象,里面是需要获取的数据
    },
    error=>{
      console.log('联系服务器失败了',error)
      return new Promise(()=>{})
    }
  )
  /* 如果response的返回值还是一个promise对象,
  则该promise对象的成功/失败的回调会作为response的返回值,
  若response的返回值为非promise对象,则response返回一个成功的回调 */
  .then(
    response=>{console.log('获取数据成功了',response)},
    error=>{console.log('获取数据失败了',error)}
  )

//简化版
try{
  const response = await fetch(url)//response接受到的是请求的状态
  const data = await response.json()//data接受到的是需要的数据
}  catch(error){console.log('请求出错',error)}//用于捕获请求失败的原因


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值