第三方库
redux
基础
import { createStore } from 'redux'
const reducer = (state = 0, action) => {
switch(action.type) {
case 'add':
return state + action.payload
case 'delete':
return state - action.payload
default:
return state
}
}
let store = createStore(reducer)
store.getState()
const action1 = {
type: 'add',
payload: 2,
}
const createAction = (val) => ({
type: 'add',
payload: val
})
store.dispatch(action1)
store.dispatch(createAction(111))
store.subscribe(() => {
console.log('change state')
})
简单实现
const createStore = (reducer, enhancer) => {
if (enhancer) {
return enhancer(createStore)(reducer)
}
let state
const getState = () => state
const dispatch = (action) => {
state = reducer(state, action)
return action
}
dispatch({})
return {
getState,
dispatch,
}
}
const compose = (...funcs) => {
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
const logger = ({
getState,
}) => next => action => {
console.log(getState());
next(action)
console.log(getState());
}
const thunk = ({
dispatch,
getState,
}) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState)
} else {
return next(action)
}
}
const applyMiddleWares = (...middlewares) => {
return (createStore) => (reducer) => {
const store = createStore(reducer)
let dispatch
let middlewareAPI = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args),
}
// const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = middlewares[0](middlewareAPI)(store.dispatch)
return {
...store,
dispatch
}
}
}
const reducer = (state = 10, action) => {
switch (action.type) {
case "ADD":
return state + action.payload
case "DELETE":
return state - action.payload
default:
return state
}
}
store = createStore(reducer, applyMiddleWares(thunk))
function fetchData(dispatch, getState) {
dispatch({
type: 'ADD',
payload: 10,
})
setTimeout(() => {
dispatch({
type: 'ADD',
payload: 30,
})
}, 2000)
}
store.dispatch(fetchData)
console.log(store.getState());
react-redux
redux
只是一个独立的状态 管理库,为了在React中使用它我们还需要一个库react-redux
。
// action.js
export const CHANGE_CHANNEL = 'CHANGE_CHANNEL'
export const changeChannel = (channel) => ({
type: CHANGE_CHANNEL,
channel
})
// reducers.js
import {
CHANGE_CHANNEL
} from './action.js'
import { combineReducers } from 'redux'
const channel = (state = "nintendo", action) => {
switch(action.type) {
case CHANGE_CHANNEL:
return action.channel
default:
return state
}
}
const name = (state = "test", action) => {
return state
}
const rootReducer = combineReducers({
channel,
name,
})
export default rootReducer
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './reducers.js'
import App from './app.js'
let store = createStore(reducer)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#root')
)
HOC用法
// app.js
import { connect } from 'react-redux'
import {
changeChannel
} from './action.js'
const App = ({
channel,
handlerClick,
}) => {
return (
<div>
<span>{channel}</span>
<button onClick={handlerClick}>Click me</button>
</div>
)
}
// 本质是运用的高阶组件,根据输入的UI组件APP生成容器组件
// mapStateToProps 把状态树中的状态映射进组件的props
const mapStateToProps = (state) => {
return {
// 组件的props 和 状态树中的state.channel对应
channel: state.channel
}
}
// mapDispatchToProps 把Dispatch方法映射为组件中props的方法
const mapDispatchToProps = (dispatch) => {
return {
handlerClick: (value) => {
dispatch(changeChannel(value))
}
}
}
// or mapDispatchToProps 也可以是个对象
// const mapDispatchToProps = {
// // 这里的函数是个action creator
// handlerClick: () => {
// type: 'add'
// }
// }
export default connect(
mapStateToProps,
mapDispatchToProps,
)(App)
Hook用法
import { useSelector, useDispatch } from 'react-redux'
const App = () => {
const channel = useSelector(state => state.channel)
const postsByChannel = useSelector(state => state.postsByChannel)
return (
<div>
<div>...</div>
</div>
)
}
react-router
import React from 'react'
import {
BrowserRouter as Router, // History mode而不是hash mode
Link,
Switch,
Route
} from 'react-router-dom' // web端用react-router-dom
function App () {
return (
<Router>
<Link to='/'>首页</Link>
<Link to='/blog'>博客</Link>
<Link to='/about'>关于我</Link>
<Switch>
<Route path='/about'>
<About />
</Route>
<Route path='/blog'>
<Blog />
</Route>
<Route path='/'>
<Home />
</Route>
</Switch>
</Router>
)
}
api
useLocation
可用于获取当前全局路由
// /profile/akara?name=aa#code
const location = useLocation()
{
hash: "#code"
pathname: "/profile/akara"
search: "?name=aa"
state: undefined
}
useHistory
可用于编程式导航
const history = useHistory()
history.push('/')
useParams
可用于获取动态路由/profile/:id
的参数id
// 当前路由/profile/akara
<Route path="/profile/:id">
<Test />
</Route>
const params = useParams() // { id: akara }
useRouteMatch
我们知道<Route path="">
的path
会和全局路由匹配,得到匹配的结果。
useRouteMatch
也是一样,用于查看全局路由和某个路径是否匹配
The
useRouteMatch
hook attempts to match the current URL in the same way that a<Route>
would
useRouteMatch
基本上有两种用法
- takes no argument and returns the match object of the current
<Route>
- takes a single argument, which is identical to props argument of matchPath. It can be either a pathname as a string (like the example above) or an object with the matching props that
Route
accepts, like this:
// 第一种用法
// 全局路由为/profile/akara
<Route path="/profile/:id">
<Test />
</Route>
function Test() {
// 不传参数,相当于拿到全局路由和<Route path="/profile/:id">的匹配结果
const match = useRouteMatch()
const {
path, // /profile/:id
url, // /profile/akara
params, // { id: akara }
} = match
return (
<div>
<Link to={`${url}/avatar`}>点击</Link>
<Route path={`${path}/avatar`}>
<div>content...</div>
</Route>
</div>
)
}
// 第二种用法
// 全局路由为/profile时,和/test匹配失败
const match = useRouteMatch({
path: '/test'
})
console.log(match); // null