react全家桶包括哪些_react 自定义组件
一、create-react-app 腳手架
對于現在比較流行的三大框架都有屬于自己的腳手架(目前這些腳手架都是使用node編寫的,并且都是基于webpack的):
- Vue的腳手架:vue-cli
- Angular的腳手架:angular-cli
- React的腳手架:create-react-app
它們的作用都是幫助我們生成一個通用的目錄結構,并且已經將我們所需的工程環境配置好。
1.1 創建項目并啟動
- 全局安裝
第一步,全局安裝:npm i -g create-react-app
第二步,切換到想創項目的目錄,使用命令:create-react-app hello-react
第三步,進入項目文件夾:cd hello-react
第四步,啟動項目:npm start - npx
npx create-react-app react_app
cd react_app
npm run start
注意:項目名稱不能使用大寫字母
1.2 項目結構
1.3 創建TS項目
create-react-app <project-name> --template typescript
npx create-react-app <project-name> --template typescript
1.4 了解PWA
全稱Progressive Web App,即漸進式WEB應用
- 一個 PWA 應用首先是一個網頁, 可以通過 Web 技術編寫出一個網頁應用
- 隨后添加上 App Manifest 和 Service Worker 來實現 PWA 的安裝和離線等功能
- 這種Web存在的形式,稱之為是 Web App
解決問題
- 可以添加至主屏幕,點擊主屏幕圖標可以實現啟動動畫以及隱藏地址欄
- 實現離線緩存功能,即使用戶手機沒有網絡,依然可以使用一些離線功能
- 實現了消息推送
- 等等一系列類似于Native App相關的功能
二、AntDesign 庫的使用
antd 的 JS 代碼默認支持基于 ES modules 的 tree shaking,對于 js 部分,直接引入 import { Button } from 'antd' 就會有按需加載的效果
2.1 在 create-react-app 中使用
// 1. 安裝
npm i antd
// 2. 修改 src/index.js,引入 antd/dist/antd.css
import 'antd/dist/antd.css'
// 3. 使用
import React from 'react'
import {
Button } from 'antd'
import './App.css'
const App = () => (
<div className="App">
<Button type="primary">Button</Button>
</div>
)
export default App
Jetbrains全家桶1年46,售后保障穩定
2.2 craco.config.js 配置
// 安裝
npm install @craco/craco
/* package.json */
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
+ "start": "craco start",
+ "build": "craco build",
+ "test": "craco test",
}
2.2.1 修改 antd 主題色
-
安裝 craco-less
npm install craco-less -
craco.config.js 配置
const CracoLessPlugin = require('craco-less') module.exports = { plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: { '@primary-color': '#1DA57A' }, javascriptEnabled: true } } } } ] } -
index.js 引入
import 'antd/dist/antd.less'
2.2.2 配置別名
const path = require('path')
const resolve = dir => path.resolve(__dirname, dir)
module.exports = {
webpack: {
alias: {
'@': resolve('src')
}
}
}
三、react-router
官網
3.1 基本使用
React Router的版本4開始,路由不再集中在一個包中進行管理了:
- react-router是router的核心部分代碼
- react-router-dom是用于瀏覽器的
- react-router-native是用于原生應用的
安裝react-router:
- 安裝react-router-dom會自動幫助我們安裝react-router的依賴
npm install react-router-dom
3.2 路由組件
3.2.1 <NavLink><Link>
相當于 vue 的 router-link,渲染成 a 標簽。
區別:
NavLink 比 Link 擁有更多的屬性,如:exact、className、activeClassName…
<NavLink className="list-group-item" to="/home">Home</NavLink>
/* 封裝<NavLink> */
// MyNavLink 組件
import React from 'react'
import {
NavLink } from 'react-router-dom'
// 傳過來的 body 內容也在 this.props.children 中
return <NavLink className="list-group-item" activeClassName="linkActive" {
...this.props} />
// 使用的組件
<MyNavLink to="/home">Home</MyNavLink>
<MyNavLink to="/about">About</MyNavLink>
3.2.2 <Switch><Routes>
可切換的路由組件,里面只顯示一個路由組件
// v5 版本及之前
<Switch>
<Route path="/about" component={
About} />
<Route path="/home" component={
Home} />
<Redirect to="/about" />
</Switch>
// v6 版本
<Routes>
<Route path="/about" component={
About} />
<Route path="/home" component={
Home} />
<Redirect to="/about" />
</Routes>
注意: v6 版本已移除 Switch,改用 Routes
3.2.3 <Redirect>
重定向組件
3.2.4 <Route>
路由渲染組件
import About from './About'
// v5 版本及之前
<Route path="/about" component={
About} />
// v6 版本
<Route path="/about" element={
<About />} />
3.2.5 <BrowserRouter><HashRouter>
相當于 vue 的 router-view,BrowserRouter 是 history 模式,HashRouter 是 hash 模式
區別:
- BrowserRouter 用的是H5的 history API,不兼容 IE9及以下版本;HashRouter 用的是 URL 的哈希值
- BrowserRouter 對路由的 state 參數沒有任何影響,因為 state 保存在 history 對象中;HashRouter 刷新后會導致 state 參數丟失
- HashRouter 可以解決一些路徑錯誤相關的問題,如:樣式丟失
3.2.6 <withRouter>
向外暴露 withRouter 包裝產生的組件(跟 connect 類似),讓非路由組件可以訪問到路由組件的 API,內部向組件傳遞路由組件特有的屬性:history/location/match
class NavFooter extends React.Component {
render() {
const navList = router
// 當前請求的路徑
const {
pathname } = this.props.location
return (
<div>{
pathname }</div>
)
}
}
export default withRouter(NavFooter)
注意: v6 版本已移除
3.3 嵌套路由
// 父級組件
import React, {
PureComponent } from 'react'
import {
NavLink, Route, Routes } from 'react-router-dom'
import About from './About'
import Profile from './Profile'
function AboutOne() {
return <div>關1于</div>
}
function History() {
return <div>歷1史</div>
}
export default class RouterPage extends PureComponent {
render() {
return (
<>
<NavLink to="/about">關于</NavLink>
<NavLink to="/profile">我的</NavLink>
<Routes>
<Route path="/about/*" element={
<About />}>
{
/* 此處不能再用 Routes 包裹 */}
<Route exact path="" element={
<AboutOne />} />
<Route path="history" element={
<History />} />
</Route>
<Route path="/profile" element={
<Profile />} />
</Routes>
</>
)
}
}
// About.js
import React, {
PureComponent } from 'react'
import {
NavLink, Outlet } from 'react-router-dom'
export default class AboutPage extends PureComponent {
render() {
return (
<>
<div>
<NavLink to="/about">關于</NavLink>
<NavLink to="/about/history">歷史</NavLink>
</div>
<Outlet />
</>
)
}
}
3.4 路由組件三大屬性(v5 及之前版本)
3.4.1 match
- params: {} // 接收動態路由傳遞的參數
- path: “” // 路由參數渲染前路徑,不包括 ?后,如 /home/:id/:title
- url: “” // 路由參數渲染后路徑,不包括 ?后,如 /home/1/標題
/* 動態路由傳參 */
// 傳數據的組件
<NavLink to={
`/home/${
1}/標題`}>Home</NavLink>
<Route path="/home/:id/:title" component={
Home} />
// 接收數據的組件
render() {
const {
id, title } = this.props.match.params
}
3.4.2 location
- pathname: “” // 路由參數渲染后路徑,不包括 ?后,如 /home/1/標題
- search: ‘“” // 路徑 ?(包括)之后的字符串
- state: {} // 主要用來傳數據
// 傳數據的組件
<NavLink to='/home?name=sunny&age=18'>Home</NavLink> // 傳的參數是公開的
<NavLink to={
{
pathname: '/home',
state: {
name: 'sunny', age: 18},
search: '?name=sunny&age=18'
}}>Home</NavLink> // 傳的參數是加密的
<Route path="/home" component={
Home} />
// 接收數據的組件
import qs from 'querystring'
/* * qs.stringify(obj) 把對象轉為路徑 * qs.parse(str) 把路徑轉為對象 */
render() {
const {
search } = this.props.location
const {
name, age } = qs.parse(search.slice(1))
const {
name } = this.props.location.state
}
3.4.3 history
相當于 vue 的 $router,常用五個屬性如下:
- push(path, [state]) // 路由跳轉,this.props.history.push({path: ‘/home’, query: {name: ‘zs’}})
- replace(path, [state]) // 路由跳轉,替換當前頁
- go(n)
- goBack()
- goForward()
3.5 react-router-config
路由管理
npm instaall react-router-config
// router > index.js 定義
import Home from '../pages/home'
import About, {
AboutHisotry, AboutCulture, AboutContact, AboutJoin } from '../pages/about'
import Profile from '../pages/profile'
const routes = [
{
path: '/',
exact: true,
component: Home
},
{
path: '/about',
component: About,
routes: [
{
path: '/about',
exact: true,
component: AboutHisotry
},
{
path: '/about/culture',
component: AboutCulture
},
{
path: '/about/contact',
component: AboutContact
},
{
path: '/about/join',
component: AboutJoin
}
]
},
{
path: '/profile',
component: Profile
}
]
export default routes
// 使用
import {
renderRoutes } from 'react-router-config'
import routes from '@/router'
// 一級路由出口
{
renderRoutes(routes)}
// 二級路由出口
{
renderRoutes(this.props.route.routes)}
四、redux
4.1 JavaScript純函數
4.1.1 定義
- 確定的輸入,一定會產生確定的輸出
- 函數在執行過程中,不能產生副作用
4.1.2 分析
為什么純函數在函數式編程中非常重要呢?
- 可以安心的寫和安心的用
- 寫的時候保證了函數的純度,只是實現自己的業務邏輯即可,不需要關心傳入的內容或者依賴其他的外部變量
- 在用的時候,確定輸入內容不會被任意篡改,并且確定的輸入,一定會有確定的輸出
4.2 Redux 的三大核心概念
4.2.1 store
單一數據源
- 整個應用程序的state被存儲在一顆object tree中,并且這個object tree只存儲在一個 store 中
- Redux并沒有強制讓我們不能創建多個Store,但是那樣做并不利于數據的維護
- 單一的數據源可以讓整個應用程序的state變得方便維護、追蹤、修改
4.2.2 action
改變 state 的唯一途徑
- 唯一修改state的方法一定是觸發action,不要試圖在其他地方通過任何的方式來修改state
- 保證所有的修改都被集中化處理,并且按照嚴格的順序來執行,所以不需要擔心race condition(竟態)的問題
4.2.3 reducer
加工 state,返回新的 state
- 通過reducer將 舊state和 actions聯系在一起,并且返回一個新的state
- 隨著應用程序的復雜度增加,可以將reducer拆分成多個小的reducers,分別操作不同state tree的一部分
- 所有的reducer都應該是純函數,不能產生任何的副作用
import {
createStore } from 'redux'
const initState = {
count: 0
}
// 創建 reducer
function reducer(state = initState, action) {
switch (action.type) {
case 'INCREMENT':
return {
...state, count: state.count + 1}
default:
return state
}
}
// 創建 store,傳入一個 reducer
const store = createStore(reducer)
// 分發 action 前訂閱 store 發生變化
store.subscribe(() => {
console.log(store.getState().count) // 1
})
// 分發 action
store.dispatch({
type: 'INCREMENT' })
4.3 Redux 結構劃分
一般放4個文件
// src > store 文件夾下
// 1. index.js
import {
createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
// 2. constants.js 定義 action 常量
export const ADD_NUMBER = 'ADD_NUMBER'
// 3. reducer.js
import {
ADD_NUMBER } from './constants'
const initState = {
count: 0
}
export default function reducer(state = initState, action) {
switch (action.type) {
case ADD_NUMBER:
return {
...state, count: state.count + action.num}
default:
return state
}
}
// 4. actionCreators.js
import {
ADD_NUMBER } from './constants'
export const addNumber = (num) => ({
type: ADD_NUMBER,
num
})
使用
import store from '@/store'
import {
addNumber } from '@/store/actionCreators'
store.subscribe(() => {
console.log(store.getState())
})
store.dispatch(addNumber(5))
4.4 react-redux 簡化使用 redux
用來簡化 react 應用中使用 redux 的一個插件
4.4.1 組件兩大類
- UI 組件
a. 只負責 UI 的呈現,不帶有任何業務邏輯
b. 通過 props 接收數據(一般數據和函數)
c. 不使用任何 Redux 的 API
d. 一般保存在 components 文件夾下 - 容器組件
a. 負責管理數據和業務邏輯,不負責 UI 的呈現
b. 使用 Redux 的 API
c. 一般保存在 containers 文件夾下
4.4.2 相關 API
-
Provider
讓所有組件都可以得到 state 數據// index.js import { Provider } from 'react-redux' import store from '@/store' ReactDOM.render( ( <Provider store={ store}> <App /> </Provider> ), document.getElementById('root') ) -
connect(mapStateToprops, mapDispatchToProps)(Counter)
- mapStateToprops(function):將外部的數據(即 state 對象)轉換為 UI 組件的標簽屬性
- mapDispatchToProps(obiect): 將分發 action 的函數轉換為 UI 組件的標簽屬性
- Counter: UI 組件
// 1.引入連接函數 import { connect } from 'react-redux' // 2.引入 action 函數 import { increment, decrement } from '@/store/actionCreators' // 3.引入 UI 組件 import Counter from './components/counter' // 4.向外暴露連接App組件的包裝組件 export default connect( state => ({ count: state}), { increment, decrement } )(Counter)
4.4.3 自定義connect函數
// context.js
import {
createContext } from 'react'
export const StoreContext = createContext()
// connect.js
import React, {
PureComponent } from 'react'
import {
StoreContext } from './context'
export function connect(mapStateToProps, mapDispatchToProps) {
return function(WrappedComponent) {
return class extends PureComponent {
static contextType = StoreContext
state = {
storeState: mapStateToProps(this.context.getState())
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
this.setState({
storeState: mapStateToProps(this.context.getState())
})
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
return <WrappedComponent
{
...this.props}
{
...mapStateToProps(this.context.getState())}
{
...mapDispatchToProps(this.context.dispatch)}
/>
}
}
}
}
// App.js
import React, {
PureComponent } from 'react'
import {
connect } from '@/utils/connect'
class Home extends PureComponent {
render() {
return (
<>
<div>Home State: {
this.props.count}</div>
<hr />
<button onClick={
() => this.props.incrementAction()}>+1</button>
</>
)
}
}
const mapStateToProps = state => ({
count: state.count
})
const mapDispatchToProps = dispatch => ({
incrementAction() {
dispatch({
type: 'increment' })
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home)
// index.js
import store from '@/store'
import {
StoreContext } from '@/utils/context'
ReactDOM.render(
<StoreContext.Provider value={
store}>
<App />
</StoreContext.Provider>,
document.getElementById('root')
)
4.4.4 hooks
import React, {
memo, useEffect } from 'react'
import {
useDispatch, useSelector, shallowEqual } from 'react-redux'
import {
getTopBannerAction } from './store/actionCreators'
// hook 形式
export default memo(function DiscoverRecommend() {
// shallowEqual 的作用是分析引用的redux數據進行淺層比較, 性能優化
const {
topBanners} = useSelector(state => ({
topBanners: state.recommend.topBanners
}), shallowEqual)
console.log(topBanners);
const dispatch = useDispatch()
useEffect(() => {
dispatch(getTopBannerAction())
}, [dispatch])
return (
<div>
DiscoverRecommend
</div>
)
})
4.5 redux-thunk 處理 redux 異步操作
默認不支持異步操作(dispatch 只支持傳入對象),需安裝 redux-thunk 中間件(可以讓dispatch支持傳入函數)
// store.js
import {
createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer.js'
const store = createStore(reducer, applyMiddleware(thunk))
export default store
第一種寫法:
// actionCreators.js
export const incrementAction = dispatch => {
setTimeout(() => {
dispatch({
type: 'INCREMENT' })
}, 300)
}
// App.js
import {
incrementAction } from '@/store/actionCreators'
const mapStateToProps = state => ({
count: state.count
})
const mapDispatchToProps = dispatch => ({
incrementAction() => {
dispatch(incrementAction)
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home)
第二種寫法(推薦):
// actionCreators.js
export const incrementAction = (num) => {
return dispatch => {
setTimeout(() => {
dispatch({
type: 'INCREMENT', num })
}, 300)
}
}
export const decrementAction = (num) => ({
type: 'DECREMENT',
num
})
// App.js
import {
incrementAction, decrementAction } from '@/store/actionCreators'
export default connect(state => ({
count: state.count
}),
{
incrementAction, decrementAction })(Home)
4.6 redux-saga 處理 redux 異步操作
npm install redux-saga
// store.js
import {
createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import saga from './saga'
// 創建sagaMiddleware中間件
const sagaMiddleware = createSagaMiddleware()
const store = createStore(reducer, composeEnhancers(applyMiddleware(sagaMiddleware)))
sagaMiddleware.run(saga)
export default store
// actionCreators.js
export const getList = () => ({
type: 'GETLIST'
})
export const changeBannersAction = (banners) => ({
type: 'CHANGE_BANNERS',
banners
})
export const changeRecommendAction = (recommends) => ({
type: 'CHANGE_RECOMMEND',
recommends
})
// saga.js
import {
takeEvery, put, all } from 'redux-saga/effects'
import {
changeBannersAction,
changeRecommendAction
} from './actionCreators'
function* fetchHomeMultidata() {
const res = yield fetch.get('http://127.0.0.1:8000/home/multidata')
const banners = res.data.data.banner.list
const recommends = res.data.data.recommend.list
// yield put(changeBannersAction(banners))
// yield put(changeRecommendAction(recommends))
yield all([
yield put(changeBannersAction(banners)),
yield put(changeRecommendAction(recommends))
])
}
function* mySaga() {
// takeLatest takeEvery區別:
// takeLatest: 依次只能監聽一個對應的action
// takeEvery: 每一個都會被執行
yield all([
takeEvery('GETLIST', fetchHomeMultidata),
// takeLatest(ADD_NUMBER, fetchHomeMultidata),
])
}
export default mySaga
4.7 使用 redux 調試工具
需先安裝 chrome 瀏覽器插件(Redux Devtools)
4.7.1 下載工具依賴包
npm install --save-dev redux-devtools-extension
使用
// store.js
import {
createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import {
composeWithDevTools } from 'redux-devtools-extension'
import reducer from './reducer'
const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)))
export default store
4.7.2 直接使用
// store.js
import {
createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
export default store
4.8 核心 API
4.8.1 createStore(reducer, [preloadedState])
創建包含指定 reducer 的 store 對象
參數
- reducer (Function): 接收兩個參數,分別是當前的 state 樹和要處理的 action,返回新的 state 樹
- [preloadedState] (any): 初始時的 state
返回值
(Store): 保存了應用所有 state 的對象。改變 state 的惟一方法是 dispatch action。你也可以 subscribe 監聽 state 的變化,然后更新 UI
import {
createStore } from 'redux'
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
}
const store = createStore(todos, ['Use Redux'])
store.dispatch({
type: 'ADD_TODO',
text: 'Read the docs'
})
console.log(store.getState())
// [ 'Use Redux', 'Read the docs' ]
4.8.2 subscribe(listener)
添加一個變化監聽器。更新 UI 視圖
// 訂閱
const unsubscribe = store.subscribe(() => {
console.log(store.getState())
})
// 取消訂閱
unsubscribe()
4.8.3 applyMiddleware(…middlewares)
應用中間件擴展 Redux
4.8.4 combineReducers(reducers)
整合 reducer,把多個 reducer 函數整合成一個對象
// reducers.js
import {
combineReducers } from 'redux'
function counter(state = 0, action) {
console.log('counter', state, action)
}
function comments(state = [], action) {
console.log('comments', state, action)
}
export default combineReducers({
counter,
comments
})
// store.js
import reducers from './reducers'
export default createStore(
reducers,
composeWithDevTools(applyMiddleware(thunk)) // 應用上異步中間件
)
4.9 自定義實現 createStore
function createStore(reducer) {
let state = reducer(undefined, {
}) // 初始化state
const list = []
function subscribe(callback) {
// 收集回調函數
list.push(callback)
}
function dispatch(action) {
state = reducer(state, action)
for (let i in list) {
// 執行回調函數
list[i] && list[i]()
}
}
function getState() {
return state
}
return {
subscribe,
dispatch,
getState
}
}
五、React SSR
5.1 SSR和同構
5.1.1 SSR
- SSR(Server Side Rendering,服務端渲染),指的是頁面在服務器端已經生成了完成的HTML頁面結構,不需要瀏覽器解析
- 對應的是CSR(Client Side Rendering,客戶端渲染),我們開發的SPA頁面通常依賴的就是客戶端渲染
- 早期的服務端渲染包括PHP、JSP、ASP等方式,但是在目前前后端分離的開發模式下,前端開發人員不太可能再去學習PHP、JSP等技術來開發網頁
- 不過我們可以借助于Node來幫助我們執行JavaScript代碼,提前完成頁面的渲染
5.1.2 同構
- 一套代碼既可以在服務端運行又可以在客戶端運行,這就是同構應用
- 同構是一種SSR的形態,是現代SSR的一種表現形式
- 當用戶發出請求時,先在服務器通過SSR渲染出首頁的內容
- 但是對應的代碼同樣可以在客戶端被執行
- 執行的目的包括事件綁定等以及其他頁面切換時也可以在客戶端被渲染
5.2 使用React SSR
-
使用React SSR主要有兩種方式:
- 方式一:手動搭建一個SSR框架;
- 方式二:使用已經成熟的SSR框架:Next.js
-
安裝Next.js框架的腳手架:
npm install –g create-next-app -
創建Next.js項目
create-next-app next-demo
5.3 路由
Next.js默認已經給我們配置好了路由映射關系:
- 路徑和組件的映射關系
- 這個映射關系就是在pages中配置相關的組件都會自動生成對應的路徑
- 默認page/index.js是頁面的默認路徑
頁面跳轉
5.4 樣式
方式一:全局樣式引入
方式二:module.css
方式三:默認集成styled-jsx
方式四:其他css in js方案,比如styled-components
- 引入相關的依賴
- 創建和編輯 .babelrc文件
npm install styled-components
npm install -D babel-plugin-styled-components
5.5 路由的嵌套及傳參
路由的嵌套(子路由):
- 文件夾的嵌套,最后就可以形成子路由
路由的傳參:
- Next.js中無法通過 /user/:id的方式傳遞參數
- 只能通過 /user?id=123的方式來傳遞參數
傳遞參數有兩種辦法:
- Link中的路徑
- Router.push(pathname, query)
六、Umi
6.1 腳手架
# 1.通過官方工具創建項目
npx @umijs/create-umi-app
# 2.安裝依賴
npm install
# 3.啟動項目
npm start
6.2 路由
umi 會根據 pages 目錄自動生成路由配置。需要注釋.umirc.js,routes相關,否則自動配置不生效
6.2.1 基礎路由
6.2.2 重定向
// pages/index.tsx 重定向到 film
import React from 'react'
import {
Redirect } from 'umi'
export default () => <Redirect to="/film"/>
// 在 film 中的 _layout.tsx
import {
Redirect } from 'umi'
export default function Film(props) {
const {
pathname } = props.location
if (pathname=== '/film' || pathname=== '/film/') {
return <Redirect to="/film/nowplaying" />
}
return <div>{
props.children }</div>
}
6.2.3 嵌套路由
6.2.4 動態路由
6.2.5 路由攔截
// center.tsx
import React from 'react'
const Center = () => {
return <div> <h1>center</h1> </div>
}
Center.wrappers = ['@/wrappers/auth']
export default Center
// wrappers/auth.tsx
import React from 'react'
import {
Redirect } from 'umi'
export default (props:any) => {
const isLogin = localStorage.getItem('token')
if (isLogin) {
return <div>{
props.children }</div>
} else {
return <Redirect to="/login" />
}
}
6.2.6 hash 模式
// .umirc.js
export default {
history: {
type: 'hash'
}
}
6.3 dva 集成
6.3.1 同步
// models/tabbar.js
export default {
// 命名空間
namespace: 'tabbar',
state: {
isShow: true
},
// 處理state--同步
reducers: {
// reducer 簡寫, type類型是show的時候自動處理
show(state, {
payload}) {
return {
...state, ...payload }
}
},
// yield表示后面的方法執行完以后 call表示調用一個api接口
// put表示一個派發
effects: {
*showEffect(payload, {
put}) {
yield put({
type:'show', payload:{
isShow:true } })
}
}
}
import {
connect, useDispatch } from 'dva'
function Detail(props) {
const dispatch = useDispatch()
useEffect(() => {
dispatch({
type: "tabbar/showEffect" // 命名空間tabbar })
}, [])
return <div> Detail </div>
}
export default connect(state => state.tabbar)(Detail)
6.3.2 異步
import {
getNowplaying } from '@/util/getNowplaying'
export default {
// 命名空間
namespace: 'list',
state: {
list: []
},
// 處理state--同步
reducers: {
changeList(state, {
payload}) {
return {
...state, ...payload }
}
},
effects: {
*getListEffect(payload, {
put}) {
const res = yield call(getNowplaying, 'test-by-kerwin')
yield put({
type:'changeList', payload:{
list: res } })
}
}
}
// util/getNowplaying
import {
fetch } from 'dva' // dva 內置的 fetch
export async function getNowplaying(value) {
console.log(value) // value 是call的第二個參數
const res = await fetch('api')
const result = await res.json()
return result.coming
}
總結
以上是生活随笔為你收集整理的react全家桶包括哪些_react 自定义组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 隐式转换函数_隐函数可以转化为显函数
- 下一篇: C# WPF 基础教程「建议收藏」