最近在忙着写自己的react个人项目。现在用到redux这块,嗯,虽然之前写过,也回顾一下,但还是有点生疏,故在此写个简单的案例,回顾一下。
有兴趣的朋友可以 于此链接 redux初识。人毕竟有遗忘曲线
计数案例
create-react-app redux-test
cd redux-est
npm run start
运行成功,开始改造
新版本默认变成如下的了,不习惯可以改成class
import React from 'react';
import './App.css';
function App() {
return (
<div className="App">
<div>ssss</div>
</div>
);
}
export default App;
函数定义组件 与 类组件的区别
- 1.函数式组件不会被实例化,整体渲染性能得到提升
函数式组件被精简成一个 render 方法的函数,所以它没有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。同时的,函数式组件本身是没有 this 的,所以在使用 Ref 等模块时与类组件也会有所区别。
- 2.函数式组件没有状态
函数式组件本身没有自己的内部状态 state,数据依赖于 props 的传入,所以它又称无状态组件。
- 3.函数式组件无访问生命周期的方法
函数式组件是不需要组件生命周期管理,所以底层实现这种形式的组件时是不会实现组件的生命周期方法。
v1.0 不用redux
import React from 'react';
import './App.css';
export default class App extends React.Component {
state = {
count:0
}
constructor(props) {
super(props)
this.numberRef = React.createRef()
}
increment = ()=>{
const number = this.numberRef.current.value*1
this.setState(state => ({count:state.count + number}))
}
decrement = ()=>{
const number = this.numberRef.current.value*1
this.setState(state => ({count:state.count - number}))
}
incrementIfOdd = ()=>{
const number = this.numberRef.current.value*1
if(this.state.count % 2 === 1){
this.setState(state => ({count:state.count + number}))
}
}
incrementAsync = ()=>{
const number = this.numberRef.current.value*1
setTimeout(()=>{
this.setState(state => ({count:state.count + number}))
},1000)
}
render(){
const count = this.state.count
return(
<div>
<p>click {count} times</p>
<div>
<select ref={this.numberRef}>
<option value = "1">1</option>
<option value = "2">2</option>
<option value = "3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>incrementIfOdd</button>
<button onClick={this.incrementAsync}>incrementAsync</button>
</div>
</div>
)
}
}
v2.0 利用redux
store.getState()
store.dispath(action)
store.subscribe(render)
store挂载在App父组件上,props传递store值,分了几个模块文件
npm install redux -S
redux/store.js
import {createStore } from "redux"
import reducer from "./reducer"
export default createStore(reducer)
redux/reducer.js
// 根据当前store和指定的action返回一个新的store
import { INCREMENT,DECREMENT} from "./action-type"
export default function count(state = 1,action) { // state的默认值可以先声明一个默认对象再赋值,这里就一个值就先这样简单处理
console.log(state,action)
switch (action.type) {
case INCREMENT:
return state + action.data
case DECREMENT:
return state - action.data
default:
return state;
}
}
redux/action-type.js
/**
* action type 统一定义,防止后续其他地方使用写错
*/
export const INCREMENT = "increment"
export const DECREMENT = "decrement"
redux/actions.js
/**
* action creators
*/
import { INCREMENT,DECREMENT} from "./action-type"
export const increment = (number) => ({type:INCREMENT,data:number})
export const decrement = (number) => ({type:DECREMENT,data:number})
App.js
import React from 'react';
import PropTypes from 'prop-types';
import { increment,decrement } from "./redux/actions"
export default class App extends React.Component {
static propTypes = {
store:PropTypes.object.isRequired
}
state = {
count:0
}
constructor(props) {
super(props)
this.numberRef = React.createRef()
}
increment = ()=>{
const number = this.numberRef.current.value*1
// this.props.store.dispatch({type:'INCREMENT',data:number}) // 不建议这样写,单独建一个actions文件
this.props.store.dispatch(increment(number))
}
decrement = ()=>{
const number = this.numberRef.current.value*1
this.props.store.dispatch(decrement(number))
}
incrementIfOdd = ()=>{
const number = this.numberRef.current.value*1
if(this.props.store.getState() % 2 === 1){
this.props.store.dispatch(increment(number))
}
}
incrementAsync = ()=>{
const number = this.numberRef.current.value*1
setTimeout(()=>{
this.props.store.dispatch(increment(number))
},1000)
}
render(){
const count = this.props.store.getState()
return(
<div>
<p>click {count} times</p>
<div>
<select ref={this.numberRef}>
<option value = "1">1</option>
<option value = "2">2</option>
<option value = "3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>incrementIfOdd</button>
<button onClick={this.incrementAsync}>incrementAsync</button>
</div>
</div>
)
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'
import store from './redux/store'
ReactDOM.render(<App store={ store } />, document.getElementById('root'));
// state更新监听
store.subscribe(()=>{ // state内部发生变化,回调 重新渲染
ReactDOM.render(<App store={ store } />, document.getElementById('root'));
})
react-redux
- Provider
- connect()
展示组件
负责组件应用的UI层面,也就是如何渲染,具有很强的内聚性,不关心渲染的数据是如何取到的
容器组件
负责应用的逻辑处理,比如发送网络请求,处理返回数据,将处理好的数据传递给展示组件等
<Provider store = {store}> //自动subscribe
connect(
state => ({})
{action1,action2} // 返回的还是dispatch()
)(UI组件)
v3.1 react-redux
重新新建文件夹Counter,App,单独测试,redux文件不变
Counter.jsx
/**
* ui组件
*/
import React from 'react';
import PropTypes from 'prop-types';
export default class Counter extends React.Component {
static propTypes = {
count:PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired,
}
state = {
count:0
}
constructor(props) {
super(props)
this.numberRef = React.createRef()
}
increment = ()=>{
const number = this.numberRef.current.value*1
this.props.increment(number)
}
decrement = ()=>{
const number = this.numberRef.current.value*1
this.props.decrement(number)
}
incrementIfOdd = ()=>{
const number = this.numberRef.current.value*1
if(this.props.count % 2 === 1){
this.props.increment(number)
}
}
incrementAsync = ()=>{
const number = this.numberRef.current.value*1
setTimeout(()=>{
this.props.increment(number)
},1000)
}
render(){
const count = this.props.count
return(
<div>
<p>click {count} times</p>
<div>
<select ref={this.numberRef}>
<option value = "1">1</option>
<option value = "2">2</option>
<option value = "3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>incrementIfOdd</button>
<button onClick={this.incrementAsync}>incrementAsync</button>
</div>
</div>
)
}
}
containers/App.js
import { connect } from "react-redux"
import Counter from "../components/Counter"
import { increment, decrement } from "../redux/actions"
/**
* 容器组件 ,通过connect包装的UI组件(Counter)
* 向UI组件传入特定的属性
*/
function mapStateToProps(state) {
return {
count: state
}
}
function mapDispatchToProps(dispatch) {
return {
increment: (number) => dispatch(increment(number)),
decrement: (number) => dispatch(decrement(number))
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter)
在起始位置的index.js改一下入口组件路径
import React from 'react';
import ReactDOM from 'react-dom';
import App from './containers/App' //修改
import store from './redux/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={ store } >
<App/>
</Provider>,
document.getElementById('root'));
v3.2 react-redux
containers/App.js 其他跟v3.1一样不变
import { connect } from "react-redux"
import Counter from "../components/Counter"
import { increment, decrement } from "../redux/actions"
export default connect(
state => ({count:state}),
{increment,decrement}
)(Counter)