简单使用
import { createStore } from "redux";
// 1. 新建 store
// 通过reducer建立
// 根据老的 state 和 action 生成新的 state
function counter(state = 0, action) {
switch (action.type) {
case "加机关枪":
return state + 1;
case "减机关枪":
return state - 1;
default:
return 10;
}
}
// 新建 store
const store = createStore(counter);
const init = store.getState();
console.log(init);
store.dispatch({ type: "加机关枪" });
console.log(store.getState());
store.dispatch({ type: "加机关枪" });
console.log(store.getState());
store.dispatch({ type: "减机关枪" });
console.log(store.getState());
优化
App.js
import React from "react";
class App extends React.Component {
// constructor(props) {
// super(props)
// }
render() {
const store = this.props.store;
const num = store.getState();
const addGun = this.props.addGun;
const removeGun = this.props.removeGun;
return (
<div>
<h1>
现在有机枪
{num}把
</h1>
<button onClick={() => store.dispatch(addGun())}>申请武器</button>
<button onClick={() => store.dispatch(removeGun())}>上交武器</button>
</div>
);
}
}
export default App;
index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore } from "redux";
import App from "./App";
import { counter, addGun, removeGun } from "./index.redux";
const store = createStore(counter);
function render() {
ReactDom.render(
<App store={store} addGun={addGun} removeGun={removeGun} />,
document.getElementById("root")
);
}
render();
store.subscribe(render);
index.redux.js
const ADD_GUN = "加机关枪";
const REMOVE_GUN = "减机关枪";
// reducer
export function counter(state = 0, action) {
switch (action.type) {
case ADD_GUN:
return state + 1;
case REMOVE_GUN:
return state - 1;
default:
return 10;
}
}
// action creator
export function addGun() {
return { type: ADD_GUN };
}
export function removeGun() {
return { type: REMOVE_GUN };
}
更进一步, 让 Redux 可以处理异步
- Redux 处理异步, 需要 redux-thunk 插件
-
npm i redux-devtools-extension
开启 - 使用 react-redux 优雅链接 react 和 redux
Redux 默认只处理同步, 异步任务需要 react-thunk 中间件
npm i redux-thunk
- 使用 applyMiddleware 开启 thunk 中间件
- Action 可以返回函数, 使用 dispatch 提交 action
App.js
render() {
const store = this.props.store
const num = store.getState()
const addGun = this.props.addGun
const removeGun = this.props.removeGun
const addGunAsync = this.props.addGunAsync
return (
<div>
<h1>现在有机枪{num}把</h1>
<button onClick={() => store.dispatch(addGun())}>申请武器</button>
<button onClick={() => store.dispatch(removeGun())}>上交武器</button>
<button onClick={() => store.dispatch(addGunAsync())}>拖两天再给</button>
</div>
)
}
index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { counter, addGun, removeGun, addGunAsync } from "./index.redux";
const store = createStore(counter, applyMiddleware(thunk));
function render() {
ReactDom.render(
<App
store={store}
addGun={addGun}
removeGun={removeGun}
addGunAsync={addGunAsync}
/>,
document.getElementById("root")
);
}
index.redux.js
export function addGunAsync() {
return dispatch => {
setTimeout(() => {
dispatch(() => {
dispatch(addGun());
});
}, 2000);
};
}
调试工具
- Chrome 搜索 redux 安装
- 新建 store 的时候判断 window.devToolsExtension
- 使用 compose 结合 thunk 和 window.devToolsExtension
- 调试窗的 redux 选项卡, 实时看到 state
// index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { counter, addGun, removeGun, addGunAsync } from "./index.redux";
const store = createStore(
counter,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : () => {}
)
);
使用 React-redux
npm i react-redux
- 忘记 subscribe, 记住 reducer, action 和 dispatch 即可
- React-redux 提供 Provider 和 connect 连个接口来链接
React-redux 具体使用
- Provider 组件在应用最外层, 传入 store 即可, 只用一次
- Connect 负责从外部获取组件需要的参数
- Connect 可以用装饰器的方式来写
// index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import App from "./App";
import { counter } from "./index.redux";
const store = createStore(
counter,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : () => {}
)
);
ReactDom.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
// App.js
import React from "react";
import { connect } from "react-redux";
import { addGun, removeGun, addGunAsync } from "./index.redux";
class App extends React.Component {
render() {
return (
<div>
<h1>
现在有机枪
{this.props.num}把
</h1>
<button onClick={this.props.addGun}>申请武器</button>
<button onClick={this.props.removeGun}>上交武器</button>
<button onClick={this.props.addGunAsync}>拖两天再给</button>
</div>
);
}
}
const mapStatetoProps = state => {
return { num: state };
};
const actionCreators = { addGun, removeGun, addGunAsync };
App = connect(
mapStatetoProps,
actionCreators
)(App);
export default App;
使用装饰器优化 Connect 代码
-
npm i -D babel-plugin-transform-decorators-legacy
安装插件 - package.json 里 babel 加上 plugins 配置
"babel": {
"presets": [
"react-app"
],
"plugins": ["babel-plugin-transform-decorators-legacy"]
}
// App.js
import React from "react";
import { connect } from "react-redux";
import { addGun, removeGun, addGunAsync } from "./index.redux";
@connect(
state => ({ num: state }),
{ addGun, removeGun, addGunAsync }
)
class App extends React.Component {
render() {
const num = this.props.num;
const addGun = this.props.addGun;
const removeGun = this.props.removeGun;
const addGunAsync = this.props.addGunAsync;
return (
<div>
<h1>
现在有机枪
{num}把
</h1>
<button onClick={addGun}>申请武器</button>
<button onClick={removeGun}>上交武器</button>
<button onClick={addGunAsync}>拖两天再给</button>
</div>
);
}
}
export default App;
验证属性
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};