store三個基本原則
- 整個應用隻有唯一一個可信資料源,也就是隻有一個 Store
- State 隻能通過觸發 Action 來更改
- State 的更改必須寫成純函數,也就是每次更改總是傳回一個新的State,在 Redux 裡這種函數稱為 Reducer
import { createStore } from 'redux';
//reducer
const initialState = {
text: 'Hello',
count: 0,
}
const reducer = (state = initialState, action) => {
console.log(action.type)
switch (action.type) {
case 'CHANGE_TEXT':
return Object.assign({},state,{
text: state.text === 'Hello' ? 'world' : 'Hello'
})
case 'BUTTON_CLICK':
return Object.assign({},state,{
text: 'Hello world'
})
case 'totalCount':
// 傳遞參數時
let count = state.count + action.params
return Object.assign({},state,{count: count})
default:
return initialState;
}
}
//store
let store = createStore(reducer);
export default store;
action基本結構
const changeTextAction = {
type: 'CHANGE_TEXT'
}
const buttonClickAction = {
type: 'BUTTON_CLICK'
}
// 需要傳遞參數時寫成這樣
let totalCountAction = (params) => {
return {
type: 'totalCount',
params
}
}
let action = {
changeTextAction,
buttonClickAction,
totalCountAction,
}
export default action;
子元件中通路store
父元件
import React from 'react';
import Test from './pages/Test';
import { connect } from 'react-redux';
import action from './store/actions'
import PropTypes from 'prop-types'
import './App.css';
class App extends React.Component {
// 想要跨級通路時需要聲明
// ----------------------------------
static childContextTypes = {
store: PropTypes.object
}
getChildContext = () => {
return {
store: this.props
}
}
//-----------------------------------
render() {
const { text, count, onButtonClick, onChangeText } = this.props;
return (
<div className="App">
<button onClick={onButtonClick}>點選觸發1</button>
<button onClick={() => onChangeText('333')}>點選觸發2</button>
<div>{count}</div>
<div>{text}</div>
<Test />
</div>
);
}
}
//映射Redux state到元件的屬性
function mapStateToProps(state) {
return { text: state.text, count: state.count }
}
//映射Redux actions到元件的屬性
function mapDispatchToProps(dispatch) {
return {
onButtonClick: () => dispatch(action.buttonClickAction),
// 傳遞參數時
onChangeText: (params) => dispatch(action.totalCountAction(params))
}
}
// 映射完成後可以this.props去通路
export default connect(mapStateToProps, mapDispatchToProps)(App);
子元件
import React,{Component} from 'react';
import PropTypes from 'prop-types'
class Test extends React.Component {
constructor (props) {
super(props);
this.state = {
}
}
// 跨級通路必備
static contextTypes = {
store: PropTypes.object
}
handleLeaveToShopkeeper = () => {
console.log(this.context.store)
this.context.store.onChangeText()
}
componentDidMount() {
const {store} = this.context;
console.log(store)
}
render () {
const {count} = this.context.store
return (<div>跨級資料{count}<button onClick={this.handleLeaveToShopkeeper}>點選觸發</button></div>)
}
}
export default Test;
mapStateToProps // 将state映射到props
mapdispatchToProps // 将dispatch映射到props
createStore(reducer) // 建立store存儲空間
connect(mapStateToProps,mapDispatchToProps,mergeProps,options) // 連結元件
childContextTypes // store跨級傳輸,頂級元件使用
getChildContext // store跨級傳輸,頂級元件使用
contextTypes // store跨級通路,子元件使用
connect詳解
ES7更新state
const initialState = {
a: 'a',
b: 'b'
};
function someApp(state = initialState, action) {
switch (action.type) {
case 'CHANGE_A':
return { ...state, a: 'Modified a' };
case 'CHANGE_B':
return { ...state, b: action.payload };
default:
return state
}
}
let state = {name: 'xyj',age: 18}
let stateOther = {...state,age: 19}
console.log(state) // {name: 'xyj', age: 18}
console.log(stateOther) // {name: 'xyj', age: 19}