react-redux的学习实现第一课:将react和redux结合起来
首先,利用create-react-app创建一个新的项目:
|__public__ index.html
|__src__ index.js
|__ Header.js
|__ Content.js
|__ ThemeSwitch.js
index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import './index.css';
import Header from './Header';
import Content from './Content';
// 创建createStore
function createStore(reducer) {
let state = null;
let listeners = [];
const getState = () => state;//初始化/获取state的函数
// 订阅事件
const subscribe = (listener) => {
listeners.push(listener);
};
const dispatch = (action) => {
state = reducer(state, action);
//每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
listeners.forEach((listener) => listener());
};
dispatch({});// 初始化一次,保证getState能够将初始化的state返回
return { getState, dispatch, subscribe };
}
// 创建reducer
function themeReducer(state, action) {
if(!state) {
return {
themeColor: 'red'
};
}
switch (action.type) {
case 'CHANGE_COLOR':
return {
...state,
themeColor: action.themeColor
};
default:
return state
}
}
const store = createStore(themeReducer);
class Index extends Component {
static childContextTypes = {
store: PropTypes.object
};
getChildContext() {
return { store };
}
render() {
return (
<div>
<Header />
<Content />
</div>
);
}
}
ReactDOM.render(<Index />, document.getElementById('root'));
Header.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
themeColor: ''
};
}
static contextTypes = {
store: PropTypes.object
};
componentWillMount() {
this._updateThemeColor();
}
_updateThemeColor = () => {
const { store } = this.context;
const state = store.getState();
this.setState({
themeColor: state.themeColor
});
};
render() {
return (
<h1 style=>我是Title</h1>
)
}
}
export default Header;
Content.js
import React, { Component } from 'react';
import ThemeSwitch from './ThemeSwitch';
import PropTypes from "prop-types";
class Content extends Component {
constructor(props) {
super(props);
this.state = {
themeColor: ''
};
}
static contextTypes = {
store: PropTypes.object
};
componentWillMount() {
this._updateThemeColor();
}
_updateThemeColor = () => {
const { store } = this.context;
const state = store.getState();
this.setState({
themeColor: state.themeColor
});
};
render() {
return (
<div>
<p style=>我是Content</p>
<ThemeSwitch />
</div>
)
}
}
export default Content;
ThemeSwitch.js
import React, { Component } from 'react';
import PropTypes from "prop-types";
class ThemeSwitch extends Component {
constructor(props) {
super(props);
this.state = {
themeColor: ''
};
}
static contextTypes = {
store: PropTypes.object
};
componentWillMount() {
this._updateThemeColor();
}
_updateThemeColor = () => {
const { store } = this.context;
const state = store.getState();
this.setState({
themeColor: state.themeColor
});
};
render() {
return (
<div>
<button style=>red</button>
<button style=>blue</button>
</div>
)
}
}
export default ThemeSwitch;
上述代码仅仅完成了store在context上的挂载,但是还没有正式开始设置颜色切换事件。 划重点:
- 本节的store是使用context去挂载的,所以在定点的父组件Index需要设置childContextTypes,否则一定报错
- 同理,子组件的contextTypes也必须要设置,否则一定报错
- 可以注意到在Index中我们初始化store的时候,我们需要将dispatch先执行一次,否则我们是没有初始化的state可用的
接下来,我们就开始在ThemeSwitch中设置颜色切换函数
handleSwitchColor = (color) => {
const { store } = this.context;
store.dispatch({
type: 'CHANGE_COLOR',
themeColor: color
});
};
但是这一段代码仍然是没有反应的,我们在Index组件中的createStore函数里面打断点看看最新的state是否更新了,如下:
function createStore(reducer) {
let state = null;
let listeners = [];
const getState = () => state;//初始化/获取state的函数
// 订阅事件
const subscribe = (listener) => {
listeners.push(listener);
};
const dispatch = (action) => {
state = reducer(state, action);
console.log('the newest state', state);
//每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
listeners.forEach((listener) => listener());
};
dispatch({});// 初始化一次,保证getState能够将初始化的state返回
return { getState, dispatch, subscribe };
}
先看一下初始化的the newest state
然后点击’blue’按钮⤵️
这说明我们切换的时候,已经成功将state修改了,看到dispatch中的listeners的时候,突然想起来,我们每一次在调用dispatch之后都需要去将修改后触发的函数推入订阅事件的队列里。现在我们开始添加订阅事件:
- 每一次修改state之后触发的函数是updateThemeColor
- 每一次调用updateThemeColor的时候,都需要从store中直接获取已经最新的state,然后调用setState去更新各个组件中的颜色
明确以上两点后,我们可以开始添加代码了。
componentWillMount() {
const { store } = this.context;
this._updateThemeColor();
store.subscribe(this._updateThemeColor);
}
将上述代码分别添加进Header/Content/ThemeSwitch中,然后刷新页面如下 初始化状态
点击blue按钮
本节学习总结:
- 每一次调用dispatch之后都需要将对应的修改状态后的函数推入事件队列,即订阅
- 修改之后,store中会保存着最新的state,各个组件只需要通过store.getState即可获得最新的state