题目:实现一个计数器,能够加一,减一,置零。主要使用了 State、Redux、React-redux 以及 React-hooks 方式。html
Demo 地址:react
import React from "react";
export default class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0
};
}
handleClick(actions) {
switch (actions) {
case "INCREASE":
return this.setState((state, props) => ({
value: ++state.value
}));
case "DECREASE":
return this.setState((state, props) => ({
value: --state.value
}));
default:
return this.setState({
value: 0
});
}
}
render() {
return (
<div> <p>{this.state.value}</p> <button onClick={() => this.handleClick("INCREASE")}>+1</button> <button onClick={() => this.handleClick("DECREASE")}>-1</button> <button onClick={() => this.handleClick("RESET")}>0</button> </div>
);
}
}
复制代码
第一步:建立 reducergit
const reducer = (state = { counter: 0 }, action) => {
switch (action.type) {
case "INCREASE":
return { counter: state.counter + 1 };
case "DECREASE":
return { counter: state.counter - 1 };
default:
return state;
}
};
复制代码
第二步:建立 actiongithub
const actions = {
increase: () => ({ type: "INCREASE" }),
decrease: () => ({ type: "DECREASE" })
};
复制代码
第三步:建立的 store,使用 createStore 方法shell
const store = createStore(reducer);
store.subscribe(() => console.log(store.getState()));
store.dispatch(actions.increase()); // {counter: 1}
store.dispatch(actions.increase()); // {counter: 2}
store.dispatch(actions.increase()); // {counter: 3}
store.dispatch(actions.decrease()); // {counter: 2}
复制代码
具体代码以下:redux
import React from "react";
import { createStore } from "redux";
const reducer = (state = { counter: 0 }, action = {}) => {
const { type } = action;
const { counter } = state;
switch (type) {
case "INCREASE":
return { counter: counter + 1 };
case "DECREASE":
return { counter: counter - 1 };
default:
return { counter: 0 };
}
};
const store = createStore(reducer);
export default class CounterRedux extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
this.unsubscribe = null;
}
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
this.setState({
counter: store.getState().counter
});
});
}
componentWillUnmount() {
// 取消订阅
this.unsubscribe();
}
render() {
return (
<div> <h1>{this.state.counter}</h1> <button onClick={() => store.dispatch({ type: "INCREASE" })}>+1</button> <button onClick={() => store.dispatch({ type: "DECREASE" })}>-1</button> <button onClick={() => store.dispatch({ type: "RESET" })}>0</button> </div>
);
}
}
复制代码
action 能够单独出来:数组
const actions = {
increase: () => ({ type: "INCREASE" }),
decrease: () => ({ type: "DECREASE" }),
reset: () => ({ type: "RESET" })
};
// 触发
<button onClick={() => store.dispatch(actions.increase())}>+1</button>;
复制代码
主要是为了展现 redux 的一个工做流程,并无把状态挂载在最顶层,详细完整版能够参考阮一峰老师的代码:Redux Counter Example。bash
Redux 的工做流程图,阮一峰博客文章摘录:app
Redux 是一款状态管理库,而且提供了 react-redux 库来与 React 亲密配合。dom
继续实现计数器,完整 Demo 能够看这里。
src 目录下大致结构:
├── actions
│ └── counter.jsx
├── components
│ └── app.jsx
├── reducers
│ └── counter.jsx
└── store
└── app.jsx
├── index.jsx
复制代码
首先,看入口文件 index.js
:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./reducers/counter.jsx";
import App from "./store/app.jsx";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById("root")
);
复制代码
Provider 组件,其实就是 Context 实现的,提供一个状态供跨组件使用,只须要把 store 给他传过去,全部的子组件就能够经过 props 属性拿到状态值。
let Context = React.createContext();
class Provider extends Component {
// 将React-redux中的Provide包装了react提供的API生成的Context.Provider
//<Provider store={xxxx}></Provider>,将store挂载在contex上
render() {
return (
<Context.Provider value={{ store: this.props.store }}> {this.props.children} //子组件 </Context.Provider> ); } } 复制代码
Reducer 函数,它接受 Action 和当前 State 做为参数,返回一个新的 State,内容和以前的几乎差很少:
import reducer from "./reducers/counter.jsx";
复制代码
// ./reducers/counter.jsx
export default function reducer(state = { counter: 0 }, action = {}) {
const { counter } = state;
const { type } = action;
switch (type) {
case "INCREASE":
return { counter: counter + 1 };
case "DECREASE":
return { counter: counter - 1 };
default:
return { counter: 0 };
}
}
复制代码
React-Redux 的核心之一 connect 方法,用于从 UI 组件生成容器组件。connect 方法接受两个参数:mapStateToProps
和 mapDispatchToProps
。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将 state 映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操做映射成 Action。
import App from "./store/app.jsx";
复制代码
// ./store/app.jsx
import { connect } from "react-redux";
import App from "./../components/app.jsx";
import {
increaseAction,
decreaseAction,
resetAction
} from "./../actions/counter.jsx";
// mapStateToProps用户本身定义须要的状态
const mapStateToProps = state => ({ counter: state.counter });
const mapDispatchToProps = dispatch => ({
onIncreaseHandle: () => dispatch(increaseAction),
onDecreaseHandle: () => dispatch(decreaseAction),
onResetHandle: () => dispatch(resetAction)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
复制代码
Action 的 type 属性:
// ./../actions/counter.jsx
export const increaseAction = { type: "INCREASE" };
export const decreaseAction = { type: "DECREASE" };
export const resetAction = { type: "RESET" };
复制代码
接着,咱们看一下熟悉的 App 组件应该怎么写:
// import App from "./../components/app.jsx";
import React from "react";
class App extends React.Component {
render() {
let {
counter,
onIncreaseHandle,
onDecreaseHandle,
onResetHandle
} = this.props;
return (
<div> <h1>{counter}</h1> <button onClick={onIncreaseHandle}>+1</button> <button onClick={onDecreaseHandle}>-1</button> <button onClick={onResetHandle}>0</button> </div>
);
}
}
export default App;
复制代码
前期作了许多工做,这里如同从父组件里获取 props 属性般获取、触发等行为,全部 store 里的 state 都经过 connect 方法给处理了:
connect(
mapStateToProps,
mapDispatchToProps
)(App);
复制代码
到这里,计数器基本的功能都好了,个人 Demo,阮一峰老师的 Demo,以及讲解的文章,Redux 入门教程(三):React-Redux 的用法,让 react 用起来更驾轻就熟——(react-redux)。
Hook 是 React 16.8 的新增特性。它可让你在不编写 class 的状况下使用 state 以及其余的 React 特性。
动机:
React Hooks 的设计目的,就是增强版函数组件,彻底不使用"类",就能写出一个全功能的组件。
React Hooks 的意思是,组件尽可能写成纯函数,若是须要外部功能和反作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}>+1</button> <button onClick={() => setCount(count - 1)}>-1</button> <button onClick={() => setCount(0)}>0</button> </div>
);
}
export default Counter;
复制代码
对比 Class Component 中将组件状态放在 state 属性中维持的作法,React Hook 使用 useState 方法来在 Function Component 中建立状态变量、建立改变状态的方法、传入初始状态。这样就实现了一个拥有本身的状态的 Function Component。
显而易见,不管是简洁程度仍是优雅程度,Function Component 都要远远优于 Class Component。
Demo 地址: