React 求和案例--redux

706 阅读6分钟

尚硅谷的代码规范

GitHub仓库地址

image.png

1. 纯react求和

image.png

Count

import React, { Component } from 'react'

export default class Count extends Component {

state = {count:0}

//加法
increment = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        this.setState({count:count+value*1})
}
//减法
decrement = ()=>{
        console.log(this.selectNumber.value);
        const {value} = this.selectNumber
        const {count} = this.state
        this.setState({count:count-value*1})
}
//奇数再加
incrementIfOdd = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        if(count % 2 !== 0){
                this.setState({count:count+value*1})
        }
}
//异步加
incrementAsync = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        setTimeout(()=>{
                this.setState({count:count+value*1})
        },500)
}

render() {
    return (
    <div>
        <h1>当前求和为:{this.state.count}</h1>
        <select ref={c => this.selectNumber = c}>
                <option value="1">1</option>
                <option value="2">2</option>
                <option value="3">3</option>
        </select>&nbsp;
    <button onClick={this.increment}>+</button>&nbsp;
    <button onClick={this.decrement}>-</button>&nbsp;
    <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
    <button onClick={this.incrementAsync}>异步加</button>&nbsp;
    </div>
    )
  }
}

App.jsx

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(<App/>,document.getElementById('root'))

2. redux精简版

image.png

1.求和案例_redux精简版
    (1).去除Count组件自身的状态
    (2).src下建立:
        -redux
                -store.js
                -count_reducer.js

    (3).store.js1).引入redux中的createStore函数,创建一个store
        2).createStore调用时要传入一个为其服务的reducer
        3).记得暴露store对象

    (4).count_reducer.js1).reducer的本质是一个函数,接收:preState,action,返回加工后的状态
        2).reducer有两个作用:初始化状态,加工状态
        3).reducer被第一次调用时,是store自动触发的,
            传递的preState是undefined,
            传递的action是:{type:'@@REDUX/INIT_a.2.b.4}

    (5).在index.js中监测store中状态的改变,一旦发生改变重新渲染<App/>
   备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

Count

yarn add redux

import React, { Component } from 'react'
//引入store,用于获取redux中保存状态
import store from '../../redux/store'

export default class Count extends Component {
/*  检测redux中状态的变化,只要变化,就调用render,但是这么写每一个用到
    redux的组件都要写componentDidMount,太过繁琐,直接在index.js文件中
    调用render。
 */
/* componentDidMount(){
    store.subscribe(()=>{
            this.setState({})
    })
} */

//加法
increment = ()=>{
    const {value} = this.selectNumber
    store.dispatch({type:'increment',data:value*1})
}
//减法
decrement = ()=>{
    const {value} = this.selectNumber
    store.dispatch({type:'decrement',data:value*1})
}
//奇数再加
incrementIfOdd = ()=>{
    const {value} = this.selectNumber
    const count = store.getState()
    if(count % 2 !== 0){
            store.dispatch({type:'increment',data:value*1})
    }
}
//异步加
incrementAsync = ()=>{
    const {value} = this.selectNumber
    setTimeout(()=>{
            store.dispatch({type:'increment',data:value*1})
    },500)
}

render() {
    return (
        <div>
            <h1>当前求和为:{store.getState()}</h1>
            <select ref={c => this.selectNumber = c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
            </select>&nbsp;
    <button onClick={this.increment}>+</button>&nbsp;
    <button onClick={this.decrement}>-</button>&nbsp;
    <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
    <button onClick={this.incrementAsync}>异步加</button>&nbsp;
        </div>
    )
  }
}

App.jsx

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App/>,document.getElementById('root'))
//只有redux里的状态发生变化,就重新调用render
store.subscribe(()=>{
	ReactDOM.render(<App/>,document.getElementById('root'))
})

store.js

/* 
   该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//暴露store,需要传入一个reducer作为参数
export default createStore(countReducer)

count_reducer.js

/* 
    1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
    2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/

const initState = 0 //初始化状态,赋给preState。初始化时preState为undefined
export default function countReducer(preState = initState, action) {
	// console.log(preState);
	//从action对象中获取:type、data
	const { type, data } = action
	//根据type决定如何加工数据
	switch (type) {
		case 'increment': //如果是加
			return preState + data
		case 'decrement': //若果是减
			return preState - data
		default:
			return preState
	}
}

3. redux完整版

image.png

比起精简版只是多了两个文件,另外dispach也不再亲自书写action对象,而是直接调用。

新增文件:

  1. count_action.js 专门用于创建action对象
  2. constant.js 放置容易写错的type值

constant.js--定义常量代替变量防止写错

/* 
  该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

count_action.js

/* 
	该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

export const createIncrementAction = data => ({type:INCREMENT,data:data})
export const createDecrementAction = data => ({type:DECREMENT,data})

count_reducer.js

/* 
    1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
    2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = {
  count:0
}//初始化状态

export default function countReducer(preState=initState,action){
	// console.log(preState);
	//从action对象中获取:type、data
	const {type,data} = action
	//根据type决定如何加工数据
	switch (type) {
		case INCREMENT: //如果是加,注意reducer是纯函数,对象中数据不能直接加
			return {...preState,count:preState.count + data}
		case DECREMENT: //若果是减
			return {...preState,count:preState.count - data}
		default:
			return preState
	}
}

store.js

/* 
   该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//暴露store,需要传入一个reducer作为参数
export default createStore(countReducer)

Count

import React, { Component } from 'react'
//引入store,用于获取redux中保存状态
import store from '../../redux/store'
//引入actionCreator,专门用于创建action对象
import {createIncrementAction,createDecrementAction} from '../../redux/count_action'

export default class Count extends Component {

    state = {carName:'奔驰c63'}

    /* componentDidMount(){
            //检测redux中状态的变化,只要变化,就调用render
            store.subscribe(()=>{
                    this.setState({})
            })
    } */

    //加法
    increment = ()=>{
            const {value} = this.selectNumber
            store.dispatch(createIncrementAction(value*1))
    }
    //减法
    decrement = ()=>{
            const {value} = this.selectNumber
            store.dispatch(createDecrementAction(value*1))
    }
    //奇数再加
    incrementIfOdd = ()=>{
            const {value} = this.selectNumber
            const count = store.getState()
            if(count % 2 !== 0){
                    store.dispatch(createIncrementAction(value*1))
            }
    }
    //异步加
    incrementAsync = ()=>{
            const {value} = this.selectNumber
            setTimeout(()=>{
                    store.dispatch(createIncrementAction(value*1))
            },500)
    }

    render() {
        return (
            <div>
                    <h1>当前求和为:{store.getState().count}</h1>
                    <select ref={c => this.selectNumber = c}>
                            <option value="1">1</option>
                            <option value="2">2</option>
                            <option value="3">3</option>
                    </select>&nbsp;
    <button onClick={this.increment}>+</button>&nbsp;
    <button onClick={this.decrement}>-</button>&nbsp;
    <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
    <button onClick={this.incrementAsync}>异步加</button>&nbsp;
            </div>
        )
    }
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App/>,document.getElementById('root'))
//只有redux里的状态发生变化,就重新调用render
store.subscribe(()=>{
	ReactDOM.render(<App/>,document.getElementById('root'))
})

App.jsx

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

4. redux--异步action

{8d118d3e-d67b-452c-a8fa-0345adb0025c}.png

Count

import React, { Component } from 'react'
//引入store,用于获取redux中保存状态
import store from '../../redux/store'
//引入actionCreator,专门用于创建action对象
import {createIncrementAction,createDecrementAction} from '../../redux/count_action'

export default class Count extends Component {


    //之前写的异步加,用了同步的action,异步操作写在了Count组件中
    incrementAsync = ()=>{
            const {value} = this.selectNumber
            setTimeout(()=>{
                    store.dispatch(createIncrementAction(value*1))
            },500)
    }
    //异步action的异步加,异步操作在count_action.js中
    incrementAsync = ()=>{
            const {value} = this.selectNumber
            // setTimeout(()=>{
                    store.dispatch(createIncrementAsyncAction(value*1,500))
            // },500)
    }
    render() {
        return (
            <div>
                    <h1>当前求和为:{store.getState()}</h1>
                    <select ref={c => this.selectNumber = c}>
                            <option value="1">1</option>
                            <option value="2">2</option>
                            <option value="3">3</option>
                    </select>&nbsp;
    <button onClick={this.increment}>+</button>&nbsp;
    <button onClick={this.decrement}>-</button>&nbsp;
    <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
    <button onClick={this.incrementAsync}>异步加</button>&nbsp;
            </div>
        )
    }
}

count_action.js

/* 
	该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(createIncrementAction(data))
		},time)
	}
}

store.js

/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//暴露store
export default createStore(countReducer,applyMiddleware(thunk))

codewhy的代码规范

GitHub仓库地址:github.com/zgcwf/React…

1. 完全版

1640849188(1).png 1640848964.png

page/about:

import React, { PureComponent } from "react";

import store from "../store";
import { subAction } from "../store/actionCreators";

export default class About extends PureComponent {
  state = {
    counter: store.getState().counter,
  };

  componentDidMount() {
    this.unSub = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter,
      });
    });
  }

  componentWillUnmount() {
    this.unSub();
  }

  render() {
    return (
      <div>
        <hr />
        <h1>About</h1>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={(e) => this.decrement()}>-1</button>
        <button onClick={(e) => this.subNumber(3)}>-3</button>
      </div>
    );
  }

  decrement() {
    store.dispatch(subAction(1));
  }

  subNumber(num) {
    store.dispatch(subAction(num));
  }
}

page/home:

import React, { PureComponent } from "react";

import store from "../store";

import { addAction } from "../store/actionCreators";

export default class Home extends PureComponent {
  state = {
    counter: store.getState().counter,
  };
  // 订阅,每次store发生变化调用render重新渲染函数
  componentDidMount() {
    this.unSub = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter,
      });
    });
  }
  // 取消订阅
  componentWillUnmount() {
    this.unSub();
  }

  render() {
    return (
      <div>
        <h1>Home</h1>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={(e) => this.increment()}>+1</button>
        <button onClick={(e) => this.addNumber(5)}>+5</button>
      </div>
    );
  }

  increment() {
    store.dispatch(addAction(1));
  }

  addNumber(num) {
    store.dispatch(addAction(num));
  }
}

constants.js

export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";

actionCreators.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
} from './constants.js';

//返回一个对象可以使用简写 
export const addAction = num => ({
  type: ADD_NUMBER,
  num
});

export const subAction = num => ({
  type: SUB_NUMBER,
  num
});

reducer.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
} from './constants.js';

const defaultState = {
  counter: 0
}

function reducer(state = defaultState, action) {
  switch (action.type) {
    case ADD_NUMBER:
      return { ...state, counter: state.counter + action.num };
    case SUB_NUMBER:
      return { ...state, counter: state.counter - action.num };
    default:
      return state;
  }
}

export default reducer;

index.js/store

import {createStore} from 'redux'

import reducer from './reducer.js';

const store = createStore(reducer);

export default store;

App.js

import React, { PureComponent } from "react";
import Home from "./pages/home";
import About from "./pages/about";
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Home />
        <About />
      </div>
    );
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
    <App />,
  document.getElementById('root')
);