redux 原理图
react-redux 改的地方
自动刷新
原本的更改需要在 index.js 下 自己手动更新,react-redux 可以自动刷新
store.subscribe(()=>{
ReactDOM.render(<App/>,document.getElementById('root'))
})
将所有组件分为两大类
- **UI组件**
- 只负责 UI 的呈现,不带有任何业务逻辑
- 通过props接收数据(一般数据和函数)
- 不使用任何 Redux 的 API
- 一般保存在components文件夹下
- **容器组件**
- 负责管理数据和业务逻辑,不负责UI的呈现
- 使用 Redux 的 API
- 一般保存在containers文件夹下
文件夹结构的优化
优化后 两大类组件UI/容器 就都放在 containers 文件夹下了
src下:
react-redux API
Provider
让所有组件都能得到 state 数据
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
connect 用于包装 UI 组件生成容器组件 ,非常重要!
import { connect } from 'react-redux'
connect(
mapStateToprops,
mapDispatchToProps
)(UIcomponent)
mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性
mapDispatchToProps:将分发action的函数转换为UI组件的标签属性
redux 开发者工具
chrome 商店
还需要下载工具依赖包npm install --save-dev redux-devtools-extension
在 store.js 中调用
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import {composeWithDevTools} from 'redux-devtools-extension'//**
import allReducers from './reducers'
export default createStore(allReducers, composeWithDevTools(applyMiddleware(thunk)));//***
简述写出一个 使用到 react-redux 的组件的流程
正常写出一个 组件 作为 UI组件,没什么要注意的。这里举例用的组件名称为 Count
使用 connect 包装UI组件,并且暴露出去
src/containers/Count/index.jsx
import { connect } from "react-redux";
import {
increment,
decrement,
incrementAsync,
} from "../../redux/actions/count";//用于 connect 的第二个参数
export default connect(
state => ({
count: state.counts,
personNumber: state.persons.length,
}),
// dispatch => ({
// increment: data => dispatch(createIncrementAction(data)),
// decrement: data => dispatch(createDecrementAction(data)),
// incrementAsync: (data, time) =>
// dispatch(createIncrementAsyncAction(data, time)),
// }),
{
increment,
decrement,
incrementAsync,
}
)(Count);
mapDispatchToProps 可以传方法也可以直接传一个对象,省略大量的 dispatch ,react-redux 会自动帮你调用 dispatch,触发对象传值的简写方式后简单明了。
connect 这里面传的东西都会作为 props 到 UI组件中,数据、方法 就都可以使用了。
src/redux/actions/count.js
然后是** /redux/actions/count**
里面要写的东西,其实一般应该是 先写了这里然后再到上面的 connect 中使用。
每个 create actions 是函数,然后都是分别暴露以供 Count 组件使用,如果是异步的就是函数中返回函数。
import { INCREMENT,DECREMENT } from "../constant";
export const increment = data => ({type: INCREMENT,data,})
export const decrement = data => ({type: DECREMENT,data,})
export const incrementAsync = (data,time) => {
return (dispatch)=>{
setTimeout(() => {
dispatch(increment(data))
},time)
}
}
注意这里的constant文件 ,里面就是存放工程所需要的所有 action 的 type 。将 type 的字符串全部存起来,防止 coder 打错字造成低级的bug。
src/redux/count.js
后厨啦,就是接受到原料 preState 和方法 action(里面有type—干什么,data—搞多少)啦,整完再传出去 newState 啦。
import { INCREMENT,DECREMENT } from "../constant";
const initState = 0
export default function countReducer(pre=initState, action) {
const { type, data } = action;
switch (type) {
case INCREMENT:
return pre + data;
case DECREMENT:
return pre - data;
default:
return pre
}
}
react-redux 在初始化时会自动调用 reducer 这时传入的第一个参数就是 undefined ,设置的初始化数据 initState 就派上用场了。
src/redux/reducers/index.js
一般后厨不止一个,那么要整合到一块成为一组传递给 store。语法也很简单,就是要用到 redux 中combineReducers
这个API了
import { combineReducers } from "redux";
import counts from "./count";
import persons from "./person";
export default combineReducers({ counts, persons });
src/redux/store.js
使用 createStore 这个函数来创造一个 store,并且暴露出去。
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import {composeWithDevTools} from 'redux-devtools-extension'
import allReducers from './reducers'
export default createStore(allReducers, composeWithDevTools(applyMiddleware(thunk)));
这里的中间件"redux-thunk"
,是有些异步操作所需要的,别问,问就是 redux API 就是如此。import allReducers from './reducers'
这句话就是从 reduces 文件下调来一个 整合的 所有 reducers,即allReducers,第二个参数composeWithDevTools就是上面提到的 因为要使用 开发者工具的依赖包。
完成
至此就完成了 一个 Count 组件,可以从 redux 获得数据来操作了。