Redux +React - 简单计数器(钩子+函数绑定写法)原理
src/
├── reducers.js
├── index.js (入口文件,用于客户端/浏览器)
├── App-simple.js (React组件-无状态函数版本)
├── App-hook.js (React组件-Hook版本)
└── App.js (React组件)
Step 1. 进入当前资源目录
$ cd /{your_directory}/react-redux-fundamentals-beginner__increment-decrement
Step 2. 确保安装了 Node 14+
. 然后安装依赖项
$ sudo npm install
Step 3. 使用 create-react-app
运行项目
$ npm run start
Step 4. 运行命令后可以通过下面的地址访问:
http://localhost:3000
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App';
//store
import { createStore } from 'redux';
import countReducer from './reducers.js'
/*
Output:
{
count: 0
}
*/
const store = createStore(countReducer);
// Whenever the store state changes, update the UI by
// reading the latest store state and showing new data
function render() {
const state = store.getState();
console.log('state: ', state);
}
// Update the UI with the initial data
render();
// And subscribe to redraw whenever the data changes in the future
store.subscribe(render);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
// Reducer
// 计数器加减
//---------
let initialState = {count: 0}
export default function countReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 }
case 'DECREMENT':
return { count: state.count - 1 }
default:
return state
}
}
React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。
它提供connect方法,用于从UI 组件生成容器组件。 connect的意思,就是将这两种组件连起来。 export default connect(mapStateToProps, mapDispatchToProps)(AppUI);
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
//from `mapDispatchToProps()`
this.props.handleIncrement();
}
render() {
//from `mapStateToProps()`
const preloadedState_count = this.props.count;
function renderCounter() {
return preloadedState_count !== null ? preloadedState_count : '';
}
return (
<React.Fragment>
<a href='#' onClick={() => { this.props.handleIncrement(); }}>Increment</a><br />
<a href='#' onClick={() => { this.props.handleDecrement(); }}>Decrement</a><br />
<h1>{renderCounter()}</h1>
</React.Fragment>
);
}
}
const mapStateToProps = (state) => {
return {
count: state.count //Receive redux
}
};
const mapDispatchToProps = (dispatch) => {
return {
handleIncrement: () => dispatch({ type: 'INCREMENT' }),
handleDecrement: () => dispatch({ type: 'DECREMENT' })
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
/* 注意: increment = () => { ... } 这种写法无需使用 bind(this) */
increment() {
this.props.dispatch({
type: "INCREMENT"
});
};
decrement() {
this.props.dispatch({
type: "DECREMENT"
});
};
componentDidMount() {
this.increment();
}
render() {
//from `mapStateToProps()`
const preloadedState_count = this.props.count;
function renderCounter() {
return preloadedState_count !== null ? preloadedState_count : '';
}
return (
<React.Fragment>
<a href='#' onClick={this.increment.bind(this)}>Increment</a><br />
<a href='#' onClick={this.decrement.bind(this)}>Decrement</a><br />
<h1>{renderCounter()}</h1>
</React.Fragment>
);
}
}
const mapStateToProps = state => {
return {
count: state.count
};
};
export default connect(mapStateToProps)(App);
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
const App = () => {
//Receive redux (useSelector钩子在概念上大致相当于 mapStateToProps 参数来连接)
const renderCounter = useSelector((state) => {
return state.count
});
// useDispatch钩子从 Redux 存储中返回对 dispatch 函数的引用
const dispatch = useDispatch();
const increment = () => {
dispatch({
type: "INCREMENT"
});
};
const decrement = () => {
dispatch({
type: "DECREMENT"
});
};
useEffect(() => {
increment();
}, [])
return (
<React.Fragment>
<a href='#' onClick={increment}>Increment</a><br />
<a href='#' onClick={decrement}>Decrement</a><br />
<h1>{renderCounter}</h1>
</React.Fragment>
);
}
export default App;