React全家桶
Redux
import { createStore } from 'redux'
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'add':
return state + 1
case 'minus':
return state - 1
default:
return state
}
}
const store = createStore(counterReducer)
export default store
import React, { Component } from 'react'
import store from '../store'
export default class ReduxTest extends Component {
render () {
return (
<div>
<p>{store.getState()}</p>
<div>
<button onClick={() => store.dispatch({ type: 'add' })}>+</button>
<button onClick={() => store.dispatch({ type: 'minus' })}>-</button>
</div>
</div>
)
}
}
import store from './store'
const render = () => {
ReactDOM.render(<App />, document.querySelector('#root'))
}
render()
store.subscribe(render)
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.querySelector('#root')
)
import React, { Component } from 'react'
import { connect } from 'react-redux'
@connect(state => ({ num: state }), {
add: () => ({ type: 'add' }),
minus: () => ({ type: 'minus' })
})
class ReduxTest extends Component {
render() {
return (
<div>
<p>{this.props.num}</p>
<div>
<button onClick={this.props.add}>+</button>
<button onClick={this.props.minus}>-</button>
</div>
</div>
)
}
}
export default ReduxTest
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'add':
return state + 1
case 'minus':
return state - 1
default:
return state
}
}
const store = createStore(counterReducer, applyMiddleware(logger, thunk))
export default store
@connect(state => ({ num: state }), {
...
asyncAdd: () => dispatch => {
setTimeout(() => {
dispatch({ type: 'add' })
}, 1000)
}
})
// reducer.js
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'add':
return state + 1
case 'minus':
return state - 1
default:
return state
}
}
export default counterReducer
// action.js
export const add = num => ({ type: 'add', payload: num })
export const minus = num => ({ type: 'minus', payload: num })
export const asyncAdd = num => dispatch => {
setTimeout(() => {
dispatch({ type: 'add', payload: num })
}, 1000)
}
// store/index.js
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import reducer from './reducer'
const store = createStore(reducer, applyMiddleware(logger, thunk))
export default store
// ReduxTest.tsx
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { add, minus, asyncAdd } from '../store/action'
@connect(state => ({ num: state }), { add, minus, asyncAdd })
class ReduxTest extends Component {
render() {
return (
<div>
<p>{this.props.num}</p>
<div>
<button onClick={this.props.add}>+</button>
<button onClick={this.props.asyncAdd}>++</button>
<button onClick={this.props.minus}>-</button>
</div>
</div>
)
}
}
export default ReduxTest
// store/index.js
import { createStore, applyMiddleware, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import reducer from './reducer'
const store = createStore(
combineReducers({
counter: reducer
}),
composeWithDevTools(applyMiddleware(logger, thunk))
)
export default store
// store/reducer.js
let defaultState = { count: 0 }
const counterReducer = (state = defaultState, action) => {
switch (action.type) {
case 'add':
return { count: state.count + 1 }
case 'minus':
return { count: state.count - 1 }
default:
return state
}
}
export default counterReducer
// store/action.js
export const add = num => ({ type: 'add', payload: num })
export const minus = num => ({ type: 'minus', payload: num })
export const asyncAdd = num => dispatch => {
setTimeout(() => {
dispatch({ type: 'add', payload: num })
}, 1000)
}
// 在组件中使用
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { add, minus, asyncAdd } from '../store/action'
class ReduxTest extends Component {
render () {
return (
<div>
<p>{this.props.num}</p>
<div>
<button onClick={this.props.add}>+</button>
<button onClick={this.props.asyncAdd}>++</button>
<button onClick={this.props.minus}>-</button>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
num: state.counter.count
})
const mapDispatchToProps = {
add,
minus,
asyncAdd
}
export default connect(mapStateToProps, mapDispatchToProps)(ReduxTest)
Router
import React from 'react'
import { BrowserRouter, Link, Route } from 'react-router-dom'
import FruitList from './FruitList'
import FruitAdd from './FruitAdd'
import Login from './Login'
import PrivateRoute from './PrivateRoute'
function Container () {
return (
<BrowserRouter>
<nav>
<Link to='/list'>水果列表</Link>
<Link to='/add'>添加水果</Link>
</nav>
<Route path='/' component={() => <div>首页</div>} />
<PrivateRoute path='/list' component={FruitList} />
<Route path='/add' component={FruitAdd} />
<Route path='/login' component={Login} />
</BrowserRouter>
)
}
export default Container
import React from 'react'
import Detail from './Detail'
import { connect } from 'react-redux'
import { Link, Route } from 'react-router-dom'
function FruitList ({ fruits }) {
return (
<div>
<ul>
{fruits.map(f => (
<li key={f}>
<Link to={`/list/detail/${f}`}>{f}</Link>
</li>
))}
</ul>
<Route path='/list/detail/:fruit' component={Detail} />
</div>
)
}
const mapStateToProps = state => ({
fruits: state.fruit.fruits
})
export default connect(mapStateToProps)(FruitList)
import React from 'react'
function Detail ({ match, history, location }) {
return (
<div>
<h1>{match.params.fruit}</h1>
<button onClick={history.goBack}>返回</button>
</div>
)
}
export default Detail
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { connect } from 'react-redux'
function PrivateRoute ({ component: Component, isLogin, ...rest }) {
return (
<Route
{...rest}
render={props =>
isLogin ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/login',
state: { redirect: props.location.pathname }
}}
/>
)
}
/>
)
}
const mapStateToProps = state => ({
isLogin: state.user.isLogin
})
export default connect(mapStateToProps)(PrivateRoute)