react随手记
目錄
組件間的通信方式
配置代理
React-router-dom
Switch,Redirect
傳遞接收params,search,state參數(shù),goBack(),goForward()
withRouter
redux+react-redux:用于多個(gè)組件間狀態(tài)共享
setState的函數(shù)寫法與對(duì)象寫法
lazy:實(shí)現(xiàn)路由懶加載、Suspense
函數(shù)式組件
useState、useEffect、useRef
Fragment
Context
PureComponent
render_props
錯(cuò)誤邊界
Fetch
創(chuàng)建腳手架命令:
create-react-app 項(xiàng)目名
組件間的通信方式
組件通信方式:
1.父子間通信:
父組件:
<child abc={xxx}/>
子組件:
props.abc拿到數(shù)據(jù)
2.兄弟間通信:
(1)消息訂閱與發(fā)布,redux集中式管理
(2)找到共同的父親,然后將數(shù)據(jù)放在父親身上,再通過子傳父和父?jìng)髯拥姆绞絹?lái)獲取數(shù)據(jù)
3.
(1)消息訂閱與發(fā)布,redux集中式管理
(2)祖孫通信Context:const {Provider,Consumer} = React.createContext()
祖先組件:
<Provider value={xxx}>
</Provider>
孫子組件:
<Consumer>
?? ?(value)=>{
?? ??? ?return()}
</Consumer>
props校驗(yàn):
安裝prop-type包,然后引入在要用的組件中import PropTypes from 'prop-type'
例如:App組件中的Porps校驗(yàn)
App.propTypes={
?? ?colors:PropTypes.array
?? ?fn:PropTypes.func.isRequired//表示傳過來(lái)的是一個(gè)函數(shù),并且是必傳項(xiàng)
}
//添加props默認(rèn)值
App.defaultProps = {
?? ?pageSize: 10//當(dāng)其他組件沒有傳pageSize值給App時(shí),默認(rèn)接收的是10
}
Router6:useNavigationType, useResolvedPath
import React from 'react' import { useNavigationType, useResolvedPath } from 'react-router-dom'export default function Demo() {/* 作用:返回當(dāng)前的導(dǎo)航類型(用戶是如何來(lái)到當(dāng)前頁(yè)面的)返回值:POP、PUSH、RESPLACE備注:POP是指在瀏覽器中直接打開了這個(gè)路由組件(刷新頁(yè)面) */console.log(useNavigationType())// 作用:給定一個(gè)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/>:當(dāng)<Route>與useRoutes()一起使用配置‘路由表‘,則需要<Outlet>來(lái)渲染子路由
Router6:params,search,state路由傳參,編程式路由導(dǎo)航navigate,navigate前進(jìn)與后退
//在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> */}{/* 對(duì)NavLink進(jìn)行二次封裝 */}<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', {// 編程式路由導(dǎo)航只能傳遞state參數(shù),params和search參數(shù)是直接寫在要跳轉(zhuǎn)的鏈接或者路由后面進(jìn)行拼接replace: false,state: {id: v.id,title: v.title}})}return (<div><ul>{state.map(v => {return (<li key={v.id}>{/* 傳遞prarms參數(shù) */}{/* <Link to={`/home/message/detail/${v.id}/${v.title}`}>{v.title}</Link> */}{/* 傳遞search(query)參數(shù) */}{/* <Link to={`/home/message/detail?id=${v.id}&title=${v.title}`}>{v.title}</Link> */}{/* 傳遞state參數(shù) */}{/* <Link to='detail' state={{id:v.id,title:v.title}}>{v.title}</Link> */}<button onClick={() => showMsgdetail(v)}>點(diǎn)擊傳遞state參數(shù)跳轉(zhuǎn)到msgdetail頁(yè)面(編程式路由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參數(shù)/* const param = useParams()const {id,title} = param */// 接收search參數(shù),修改search參數(shù)的方法/* const [search,setSearch] = useSearchParams()const id = search.get('id')const title = search.get('title') */// 接收state參數(shù)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參數(shù)的方法 */}{/* <button onClick={()=>setSearch("id='7'&title='hhh'")}>點(diǎn)擊改變search參數(shù)</button> */}</p>)}//在Header非路由組件中實(shí)現(xiàn)前進(jìn)與后退: import React, { Component } from 'react' import { useNavigate } from 'react-router-dom'function Header() {const navigate = useNavigate()function goBack(){// router5// this.props.history.goBack()// router6navigate(-1)}function goForward(){// this.props.history.goForward()navigate(1)}return (<div className='react_header'><h2>React-router-dom</h2><button onClick={goBack}>回退</button> <button onClick={goForward}>前進(jìn)</button></div>)}export default HeaderRouter6hook:useResolvedPath()
//作用:給定一個(gè)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:接收一個(gè)函數(shù)<NavLink className={computeClassName} to='/navigate'>navigate</NavLink> <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:指定跳轉(zhuǎn)到指定頁(yè)面 */}{sum==2?<Navigate to='/error'/>:<h2>sum:{sum}</h2>}<button onClick={()=>setSum(2)}>點(diǎn)擊sum變?yōu)?</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> <NavLink to='/error'>error</NavLink><div>{element}</div></div>)}export default AppuseCallback
// 防止因?yàn)榻M件重新渲染,導(dǎo)致方法被重新創(chuàng)建,起到緩存作用,只有第二個(gè)參數(shù)變化,才重新聲明渲染const Fun = useCallback(()=>{// 函數(shù)()=>{}},[name])useMemo
const a = useMemo(()=>{// 函數(shù)()=>{}},[name]) //與Vue中的compute屬性類似,a得到的結(jié)果是useMemo第一個(gè)函數(shù)參數(shù)的返回值,第二個(gè)參數(shù)是監(jiān)測(cè)改變的數(shù)據(jù) //如果數(shù)組中的name沒有發(fā)生變化,則函數(shù)會(huì)采取緩存的方式,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
Link,NavLink
//在src/index.js中 import {BrowserRouter} from 'react-router-dom' //import {HashRouter} from 'react-router-dom':可以解決刷新頁(yè)面后樣式丟失問題#后面默認(rèn)為是前端資源,不帶給服務(wù)器 ReactDOM.render(<BrowserRouter><App/></BrowserRouter>,document.getElementById('root') )//在組件中 import {Link ,Route} from 'react-router-dom' //路由鏈接 //<Link className="item" to="/about">路由跳轉(zhuǎn)</Link> //NavLink中有一個(gè)屬性activeName:點(diǎn)擊跳轉(zhuǎn)到哪個(gè)路由哪個(gè)標(biāo)簽高亮 <NavLink activeName="abc" className="item" to="/about">路由跳轉(zhuǎn)到about</Link> <NavLink activeName="abc" className="item" to="/home">路由跳轉(zhuǎn)home</Link> //注冊(cè)路由 <Route path="/about" component={About}/>NavLink的二次封裝
//在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> */}{/* 對(duì)NavLink進(jìn)行二次封裝 */}<MyNavLink to="/about">about</MyNavLink><MyNavLink to="/home">home</MyNavLink> //在MyNavLink中通過this.props.children可以獲取該標(biāo)簽體中的內(nèi)容,而無(wú)需與vue一樣使用插槽</ul><div className='content_right'>//exact:開啟精準(zhǔn)匹配<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與對(duì)應(yīng)component匹配到之后就不再往下繼續(xù)匹配 //在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中重定向路由,默認(rèn)頁(yè)面一開始就展示about頁(yè)面<Redirect to="about"/> </Switch>*/<Routes className="route"> //caseSensitive :指定path匹配時(shí)是否區(qū)分大小,寫默認(rèn)為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參數(shù),goBack(),goForward()
//在message組件中: // 傳遞params參數(shù)// 傳遞params參數(shù)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進(jìn)行路由跳轉(zhuǎn)pushShow = (id,title)=>{// 接收state參數(shù)進(jìn)行路由跳轉(zhuǎn)this.props.history.push('/home/message/detail',{id:id,title:title})//this.props.history.goBack()//回退}replaceShow = (id,title)=>{// 接收state參數(shù)進(jìn)行路由跳轉(zhuǎn)this.props.history.replace('/home/message/detail',{id:id,title:title})//this.props.history.goForward()//前進(jìn)}render() {return (<div><ul>{this.state.messageList.map(v=>{return (<li key={v.id}>{/* 傳遞prarms參數(shù) */}{/* <Link to={`/home/message/detail/${v.id}/${v.title}`}>{v.title}</Link> */}{/* 傳遞search(query)參數(shù) */}{/* <Link to={`/home/message/detail?id=${v.id}&title=${v.title}`}>{v.title}</Link> */}{/* 傳遞state參數(shù) 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)}>編程式路由無(wú)歷史緩存replace</button></li>)})}{/* 聲明接受query參數(shù) */}{/* <Route path="/home/message/detail/:id/:title" component={Msgdetail}/> */}{/* 接收search,state參數(shù),都無(wú)需聲明 */}<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參數(shù)// const {id,title} = this.props.match.params//接收search參數(shù)// id=1&title=msg1:是urlencode的編碼形式/* const {search} =this.props.locationlet searchquery = qs.parse(search.slice(1))const {id,title} =searchquery */// 接收state參數(shù):導(dǎo)航欄中不顯示傳遞的參數(shù)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> <button onClick={this.goForward}>前進(jìn)</button></div>)} }//widthRouter:加工非路由組件,讓非路由組件也具有路由組件中的Api(如:this.props中的值),widthRouter的返回值是一個(gè)新組件 export default withRouter(Header)redux+react-redux:用于多個(gè)組件間狀態(tài)共享
//在index.js入口文件中: import React from 'react'//JSX語(yǔ)法需要 import {createRoot} from 'react-dom/client'//可以幫我們把React組件渲染到頁(yè)面上去 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傳給每一個(gè)容器組件<Provider store={store}><App/></Provider>) // 獲取到redux中的數(shù)據(jù)后即使更新組件(如果使用了react-redux第三方庫(kù),則無(wú)需subscribe監(jiān)測(cè)組件狀態(tài)的變化 /* 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' // 統(tǒng)一在index.js中使用react-redux第三方庫(kù)提供的Provider組件來(lái)將store傳給每一個(gè)容器組件 // 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接收函數(shù)為返回值可以被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 } = actionswitch (type) {case 'increment':return preState + datacase 'decrement':return preState - datadefault :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} = actionswitch(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的返回值為一個(gè)對(duì)象,則為同步action export const createDecrementAction = data => ({type:DECREMENT,data})export const createIncrementAsyncAction = (data,time)=>{// 由store調(diào)用,傳入dispatch參數(shù)// 如果action的返回值為一個(gè)函數(shù),則為異步actionreturn (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.myRefthis.props.createIncrementAction(value*1)}decrement = ()=>{const {value} = this.myRefthis.props.createDecrementAction(value*1)}incrementOdd = ()=>{const {value} = this.myRefconst count = this.props.countif(count%2!==0){// store.dispatch(createIncrementAction(value*1))// 借用react-redux第三方庫(kù)為中間人this.props.createIncrementAsyncAction(value*1)}}incrementAsync = ()=>{const {value} = this.myRefthis.props.jiaAsync(value*1,500)}render() {const {count,personNumber} =this.statereturn (<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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementOdd}>奇數(shù)+</button> <button onClick={this.incrementAsync}>異步+</button> </div>)} }// 接收count組件的狀態(tài),返回值是一個(gè)對(duì)象 /* const mapStateToProps = (state)=>{return {count:state} } */ // 接收count組件的方法,返回值是一個(gè)對(duì)象 // 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簡(jiǎn)化版// 第二個(gè)參數(shù)可以接收一個(gè)function,也可以接收一個(gè)對(duì)象{createIncrementAction,//react-redux默認(rèn)會(huì)幫忙調(diào)用dispatchcreateDecrementAction,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.nameReflet {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='請(qǐng)輸入名字' ref={v=>this.nameRef=v}/> <input type="text" placeholder='請(qǐng)輸入年齡' ref={v=>this.ageRef=v}/> <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的函數(shù)寫法與對(duì)象寫法
import React, { Component } from 'react'export default class Count extends Component {state = {count:0}add = ()=>{// this.setState對(duì)象寫法/* this.setState({count:this.state.count+1},()=>{console.log(this.state.count,'對(duì)象寫法回調(diào)函數(shù)------')//1}) */// this.setState函數(shù)寫法this.setState((state,props)=>{return ({count:state.count+1})},()=>{console.log(this.state.count,'函數(shù)寫法回調(diào)函數(shù)------')})// console.log(this.state.count):0}// setState異步更新狀態(tài),接收兩個(gè)參數(shù)({},()=>{}):()=>{}:在setState異步更新狀態(tài)結(jié)束后,并且render調(diào)用后執(zhí)行render() {return (<div><div>Count的值為:{this.state.count}</div><button onClick={this.add}>點(diǎn)擊+1</button></div>)} }lazy:實(shí)現(xiàn)路由懶加載、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:用于指定頁(yè)面出錯(cuò)加載不出來(lái)時(shí)而展示給用戶看的頁(yè)面 ,fallback:接收一個(gè)組件*/}<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函數(shù)式組件
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}>點(diǎn)擊+1</button><button onClick={this.unMount}>點(diǎn)擊卸載組件</button></div>)} } */ export default function FunUse(){const [count,setCount] = React.useState(0)const myRef = React.useRef()/* React.useEffect(()=>{},[]):第二個(gè)參數(shù)為[]時(shí)=componentDidMount,不寫第二個(gè)參數(shù)時(shí)=componentDidUpdated第二個(gè)參數(shù)為[count]:表示只監(jiān)測(cè)count狀態(tài)的改變,只有count狀態(tài)改變才會(huì)重新調(diào)用useEffect,useEffect()的第一個(gè)參數(shù)接收一個(gè)函數(shù)作為返回值,該返回值的函數(shù) = componentWillUnmount*/React.useEffect(()=>{let timer = setInterval(()=>{// 在useEffect中使用定時(shí)器時(shí)只能使用函數(shù)的更新方式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}/> <button onClick={getData}>點(diǎn)擊獲取input框中的值(useRef)</button><h2>Count的值為:{count}</h2><button onClick={increment}>點(diǎn)擊+1(useState)</button> <button onClick={unMount}>點(diǎn)擊卸載組件(useEffect)</button> </div>) }Fragment
import React, { Component ,Fragment} from 'react'export default class Fragment extends Component {render() {return (<Fragment>{/* 作為根標(biāo)簽,不會(huì)渲染到頁(yè)面上 */}</Fragment>)} }Context
import React, { Component ,Fragment} from 'react'// 創(chuàng)建Context容器對(duì)象 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>{// 用一個(gè)函數(shù)接收從祖先傳過來(lái)的值,該函數(shù)的參數(shù)就是祖先傳過來(lái)的valueval=><span>從祖先接收過來(lái)的值:{val}</span>}</MyContext.Consumer>) }PureComponent
import React, { PureComponent } from 'react'/* PureComponent與Component的:Component的2個(gè)問題:1.只要執(zhí)行setState(),即使不改變狀態(tài)數(shù)據(jù),組件也會(huì)重新render()2.只要當(dāng)前組件重新render(),即使子組件沒有接收任何父組件的數(shù)據(jù),也會(huì)自從重新render子組件==>效率低PureComponent:底層重寫了shoudComponentUpdate(),只有state或props數(shù)據(jù)有變化時(shí)才返回true注意:只是進(jìn)行state與props數(shù)據(jù)的淺比較,如果只是數(shù)據(jù)對(duì)象內(nèi)部數(shù)據(jù)變化了,則shoudComponentUpdate()會(huì)返回false,不更新頁(yè)面 */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組件中的標(biāo)簽體內(nèi)容// console.log(this.props.children)return (<div>{/* 調(diào)用父組件中傳過來(lái)的render函數(shù) */}B:{this.props.render(name)}</div>)} }class C extends Component {render() {return (<div>接收從父組件B中傳來(lái)的name:{this.props.name}</div>)} }錯(cuò)誤邊界
import React, { Component } from 'react'export default class Parent extends Component {state = {hasError: ''}// 生命周期函數(shù),當(dāng)parent的子組件出現(xiàn)報(bào)錯(cuò)時(shí),會(huì)觸發(fā)getDerivedStateFromError調(diào)用,并攜帶錯(cuò)誤信息static getDerivedStateFromError(error) {return { hasError: error }}componentDidCatch(){console.log('此處常用于統(tǒng)計(jì)錯(cuò)誤次數(shù)法,反饋給服務(wù)器,通知程序員修改')}render() {return (<div><p>Parent組件</p>{this.state.hasError ? <h2>當(dāng)前網(wǎng)絡(luò)不穩(wěn)定,請(qǐng)稍后再試</h2> : <Child />}<div>子組件即使報(bào)錯(cuò)也能正常渲染</div></div>)} }class Child extends Component {state = {// 數(shù)據(jù)錯(cuò)誤,本來(lái)是數(shù)組但是寫出字符串使得遍歷people的時(shí)候報(bào)錯(cuò),// 則需要用錯(cuò)誤邊界在父組件中進(jìn)行攔截錯(cuò)誤,使得頁(yè)面正常渲染people: ''}render() {return (<div>{this.state.people.map(v => {return <li key={v.id}>v</li>})}</div>)} }Fetch
//使用fetch發(fā)送網(wǎng)絡(luò)請(qǐng)求(瀏覽器自帶)//不簡(jiǎn)化寫法fetch(url).then(response=>{//該response拿到的是請(qǐng)求的狀態(tài)console.log('聯(lián)系服務(wù)器成功了')return response.json()//返回一個(gè)promise的對(duì)象,里面是需要獲取的數(shù)據(jù)},error=>{console.log('聯(lián)系服務(wù)器失敗了',error)return new Promise(()=>{})})/* 如果response的返回值還是一個(gè)promise對(duì)象,則該promise對(duì)象的成功/失敗的回調(diào)會(huì)作為response的返回值,若response的返回值為非promise對(duì)象,則response返回一個(gè)成功的回調(diào) */.then(response=>{console.log('獲取數(shù)據(jù)成功了',response)},error=>{console.log('獲取數(shù)據(jù)失敗了',error)})//簡(jiǎn)化版 try{const response = await fetch(url)//response接受到的是請(qǐng)求的狀態(tài)const data = await response.json()//data接受到的是需要的數(shù)據(jù) } catch(error){console.log('請(qǐng)求出錯(cuò)',error)}//用于捕獲請(qǐng)求失敗的原因總結(jié)
- 上一篇: CDH集群搭建(CDH 6.0.1)
- 下一篇: 浏览器访问服务器的流程