设计思想
(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。
HTML
Copy
Store
Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
Redux 提供createStore这个函数,用来生成 Store
import { createStore } from 'redux';
const store = createStore(fn);
HTML
Copy
State
Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。
当前时刻的 State,可以通过store.getState()拿到
import { createStore } from 'redux';
const store = createStore(fn);
const state = store.getState();
HTML
Copy
Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。
Action
State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。
可以这样理解,Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。
store.dispatch()
store.dispatch()是 View 发出 Action 的唯一方法。
import { createStore } from 'redux';
const store = createStore(fn);
store.dispatch({
type: 'ADD_TODO',
payload: 'Learn Redux'
});
HTML
Copy
上面代码中,store.dispatch接受一个 Action 对象作为参数,将它发送出去。
store.dispatch(addTodo('Learn Redux'));
HTML
Copy
Reducer
Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
store.subscribe()
Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
HTML
Copy
store.subscribe方法返回一个函数,调用这个函数就可以解除监听
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
);
unsubscribe();
HTML
Copy
(1)Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
(2)View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。
(3)Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
store 是包含所有数据
而想要store 需要使用createStore(reducer)
获取当前state 使用 store.getStore();
数据监听使用store.subscribe();
而action 是一种形为,需要使用 store.dispatch(action)
而上面的reducer 是一收到对应的action 而反回新的数据state
使用dispatch 两种方式
一是直接使用
connect(mapStateToProps,null)(View);
第二个参数 为空,这样页面直接可以使用this.props 使用
二是使用使用mapDispatchToProps
export default connect(mapStateToProps,mapDispatchToProps)(View);
直接使用 mapDispatchToProps 内的方法
React JSX
Copy
第一步:
yarn add react-redux redux
第二步:
router store 注入
import store from ‘./Store.js’;
整个页面的store(数据仓库)
第三步
我需要创建 Store.js
引入 多个 reducer (store数据片段)
combineReducers 合并整合多个reducer
再进行 createStore()
第一参数 reducer (纯函数,返回新的state)
第二个参数 state 初始化值 null
第三个 中间件
到这个位置
router 基本不需要再修改了
store 只需引入 所需 view下的页面中的reducer
createStore
第四步
关于每个view 页面
views
home
每个页面都需要一个state
state 如何生成 Reducer(返回新的state)
action
对象 return{}
type 每个action 名称
ActionTypes
reducer
根据具体的action 名称(type对应)
来编写或计算返回新的state
[...new,..state]
Object.assign()
以上是具体当前view 页面内部以外的redux
jsx
about
每个页面都需要一个state
news
每个页面都需要一个state
usercenter
每个页面都需要一个state
第五步
如何与页面交互
导入
import {connect} from ‘react-redux’;
导出
export default connect(mapStateToProps,mapDispatchToProps)(View);
function mapStateToProps(state) {
return {
isList:state.add
}
}
state.add
add 是哪来的 就是我们Store.js
自定义的reducer
const reducer = combineReducers({
add:addReducer,
// remove:removeReducer,
// edit:editReducer,
})
isList
当前组件 this.props 可以接受到
const {onAddFn,isList,onRemoveFn} = this.props;
轻松的拿到对应 reducer 返回的 State
怎么操作 action
//是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。
const mapDispatchToProps = (dispatch, ownProps) => {
// const {id} = ownProps;
return {
onAddFn: () => dispatch(AddTodo(‘add’))
}
};
onAddFn: () => dispatch(AddTodo(‘add’))
dispatch 操作action
onAddFn 通过this.props 来使用
onClick = {onAddFn}
onAddFn 为自定义 在当前view 页面使用
test(){
// connect(mapStateToProps,null)(View);
// 只有第二个参数 为空时 才 可以直接使用this.props 否则页面无法获取
// const {dispatch} = this.props;
// dispatch(actions.add('id'))
console.log(this.props)
}
React JSX
Copy
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {actions} from './_index.js';
class View extends Component {
constructor(props){
super(props);
// const { dispatch } = props;
// this.boundActions = bindActionCreators(actions, dispatch);
}
lists(){
const list = this.props.data.map((val,key)=>{
return(
<li key={key}>
<span>{val.text}</span>
</li>
)
})
return list;
}
test(){
// connect(mapStateToProps,null)(View);
// 只有第二个参数 为空时 才 可以直接使用this.props 否则页面无法获取
// const {dispatch} = this.props;
// dispatch(actions.add('id'))
console.log(this.props)
}
componentDidMount(){
this.test()
}
render(){
const { onAdd ,data} = this.props;
// console.log(data)
return(
<React.Fragment>
<div onClick={onAdd}>点我点</div>
<div onClick={()=>{this.test()}}>点我点</div>
<ul>{data.length!==0 ? this.lists() : ''}</ul>
</React.Fragment>
)
}
}
//需要渲染什么数据
//作为函数,mapStateToProps执行后应该返回一个对象
function mapStateToProps(state) {
return {
data:state.first
}
}
//是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onAdd: () => dispatch(actions.add('id'))
}
};
export default connect(mapStateToProps,mapDispatchToProps)(View);
```
```jsx
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {actions} from './_index.js';
class View extends Component {
constructor(props){
super(props);
// const { dispatch } = props;
// this.boundActions = bindActionCreators(actions, dispatch);
}
lists(){
const list = this.props.data.map((val,key)=>{
return(
<li key={key}>
<span>{val.text}</span>
</li>
)
})
return list;
}
test(){
// connect(mapStateToProps,null)(View);
// 只有第二个参数 为空时 才 可以直接使用this.props 否则页面无法获取
const {dispatch} = this.props;
dispatch(actions.add('id'))
console.log(this.props)
}
componentDidMount(){
this.test()
}
render(){
const { onAdd ,data} = this.props;
// console.log(data)
return(
<React.Fragment>
<div onClick={onAdd}>点我点</div>
<div onClick={()=>{this.test()}}>点我点</div>
<ul>{data.length!==0 ? this.lists() : ''}</ul>
</React.Fragment>
)
}
}
//需要渲染什么数据
//作为函数,mapStateToProps执行后应该返回一个对象
function mapStateToProps(state) {
return {
data:state.first
}
}
//是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onAdd: () => dispatch(actions.add('id'))
}
};
export default connect(mapStateToProps,null)(View);