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跨级访问,子组件使用
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}