在没有react-redux之前我们想要操作store:
- 第一种选择是从根节点一直向下传递store
- 第二种选择是组件中声明childContextTypes并定义Context(上篇文章有Demo)
这种每个组件都要显式定义context或者是显式传递store对于我们的代码来说算是一种小的灾难性(当然并不会影响太多),会导致我们写很多重复代码,也有些不易于维护逻辑。
react-redux就帮助我们解决了这个问题。使我们可以将逻辑和UI分离,易于维护。但同时也产生了一些问题,我的个人看法,这里就不做阐述了。
个人推荐的使用react-redux的写法是将容器组件(也就是UI组件的逻辑部分)和UI组件分文件来管理。但由于个人比较懒,就都放到了UI层来写了。(手动滑稽…)
这篇文章的Demo可以和我上篇Redux的Demo来进行对比,就能看到react-redux的优势和缺点了。有得必有失,世间之事皆如此。
Demo
index
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import store from "./chapter9-react-redux/store";
import App from "./chapter9-react-redux/App";
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
App
import React from 'react';
import ItemList from "./ItemList";
import AddItemForm from "./AddItemForm";
const App = (props) => {
return (
<div>
<AddItemForm/>
<ItemList/>
</div>
)
}
export default App;
AddItemForm
import React from 'react';
import {addItem} from "./actions";
import {connect} from 'react-redux';
const AddItemForm = (props) => {
let {addItem} = props;
let title;
const submit = e => {
e.preventDefault();
addItem(title.value);
title.value = '';
title.focus();
}
return (
<form onSubmit={submit}>
<input type="text"
ref={input => title = input}
/>
<button>ADD</button>
</form>
)
}
function mapDispatchToProps(dispatch) {
return {
addItem: (title) => dispatch(addItem(title))
}
}
export default connect(null, mapDispatchToProps)(AddItemForm);
ItemList
import React from 'react';
import {connect} from 'react-redux';
import Item from "./Item";
const ItemList = (props) => {
const {Items} = props;
console.log(Items)
return (
<ul>
{
Items.length === 0 ?
<p>No item List. (Add a Item)</p> :
Items.map((item, index) =>
<Item key={item.id}
{...item}/>
)
}
</ul>
)
}
function mapStateToProps(state) {
return {
Items: state.Items
}
}
export default connect(mapStateToProps, null)(ItemList);
Item
import React from 'react';
import {removeItem} from "./actions";
import {connect} from "react-redux";
const Item = (props) => {
const {id, title, removeItem} = props;
return (
<li>
{title}
<button onClick={() => removeItem(id)}>X</button>
</li>
)
}
function mapDispatchToProps(dispatch) {
return {
removeItem: (id) => dispatch(removeItem(id))
}
}
export default connect(null, mapDispatchToProps)(Item);
Action
import {v4} from "uuid";
import Constants from "../Constants";
export const addItem = title => ({
type: Constants.ADD_ITEM,
id: v4(),
title
})
export const removeItem = id => ({
type: Constants.REMOVE_ITEM,
id
})
Reducer
import Constants from "../Constants";
const Item = (state = {}, action) => {
switch (action.type) {
case Constants.ADD_ITEM:
return {
id: action.id,
title: action.title
}
default:
return state;
}
}
export const Items = (state = [], action) => {
switch (action.type) {
case Constants.ADD_ITEM:
return [
...state,
Item({}, action)
]
case Constants.REMOVE_ITEM:
return state.filter((item, index) =>
item.id !== action.id
)
default:
return state;
}
}
Store
import {createStore, combineReducers} from "redux";
import {Items} from "../reducers";
const store = createStore(combineReducers({Items}));
export default store;
Constant
const Constants = {
ADD_ITEM: "ADD_ITEM",
REMOVE_ITEM: "REMOVE_ITEM"
}
export default Constants