[尚硅谷React笔记]——第7章 redux

news2024/11/16 19:30:05

目录:

  1. redux简介
  2. redux工作流程
  3. 求和案例_纯react版
  4. 求和案例_redux精简版
  5. redux完整版
  6. 异步action版
  7. 对react-redux的理解
  8. 连接容器组件与UI组件,react-redux基本使用
  9. 优化1_简写mapDispatch
  10. 优化2_Provider组件的使用
  11. 优化3_整合UI组件与容器组件
  12. 数据共享_编写Person组件,编写Person组件的reducer,完成数据共享
  13. 纯函数
  14. 高阶函数:
  15. redux开发者工具
  16. 最终版
  17. 项目打包运行
  18. 项目地址 

1.redux简介

 redux是什么?

  1. redux是一个专门用于做状态管理的JS库(不是react插件库)。
  2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
  3. 作用: 集中式管理react应用中多个组件共享的状态。

 什么情况下需要使用redux?

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)。
  2. 一个组件需要改变另一个组件的状态(通信)。
  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。

2.redux工作流程

redux工作流程:

redux的三个核心概念

action

  1. 动作的对象
  2. 包含2个属性
    1. type:标识属性, 值为字符串, 唯一, 必要属性
    2. data:数据属性, 值类型任意, 可选属性
  3. 例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }

reducer

  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的state和action, 产生新的state的纯函数

store

  1. 将state、action、reducer联系在一起的对象
  2. 如何得到此对象?
    1. import {createStore} from 'redux'
    2. import reducer from './reducers'
    3. const store = createStore(reducer)
  3. 此对象的功能?
    1. getState(): 得到state
    2. dispatch(action): 分发action, 触发reducer调用, 产生新的state
    3. subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

3.求和案例_纯react版 

Count.jsx

import React, {Component} from 'react';

class Count extends Component {
    state = {count: 0}
    increment = () => {
        const {value} = this.selectNumber
        const {count} = this.state
        this.setState({count: count + value * 1})
    }

    decrement = () => {
        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>
        );
    }
}

export default Count;

 4.求和案例_redux精简版

  • 去除Count组件自身的状态
  • src下建立:
    • -src
      • -redux
        • -store.js
        • -count_reducer.js
  • store.js:
    • 引入redux中的createStore函数,创建一个store
    • createstore调用时要传入一个为其服务的reducer
    • 记得暴露store对象
  • count_reducer.js:
    • reducer的本质是一个函数,接收: preState,action,返回加工后的状态
    • reducer有两个作用:初始化状态,加工状态
    • reducer被第一次调用时,是store自动触发的,传递的preState是undefined
  • 在index.js中检测store中状态的改变,一旦发生改变重新渲染<App/>
  • 备注: redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

Count.jsx

import React, {Component} from 'react';
import store from '../../redux/store'

class Count extends Component {
    state = {carName: '奔驰c63'}

    // 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>车名字:{this.state.carName}</h1>
                <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>
        );
    }
}

export default Count;

 store.js

import {createStore} from 'redux'
import countReducer from './count_reducer'

export default createStore(countReducer)

count_reducer.js

const initState = 0

export default function countReducer(preState = initState, action) {
    const {type, data} = action

    switch (type) {
        case 'increment':
            return preState + data
        case 'decrement':
            return preState - data
        default:
            return preState
    }
}

index.js

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

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<App/>);

store.subscribe(() => {
    root.render(<App/>);
})

5.redux完整版

新增文件:

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

Count.jsx

import React, {Component} from 'react';
import store from '../../redux/store'
import {createIncrementAction, createDecrementAction} from '../../redux/count_action'

class Count extends Component {
    state = {carName: '奔驰c63'}

    // componentDidMount() {
    //     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>车名字:{this.state.carName}</h1>
                <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>
        );
    }
}

export default Count;

constant.js

export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'

count_action.js

import {DECREMENT, INCREMENT} from "./constant";


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

count_reducer.js

import {INCREMENT, DECREMENT} from "./constant";

const initState = 0

export default function countReducer(preState = initState, action) {
    const {type, data} = action

    switch (type) {
        case INCREMENT:
            return preState + data
        case DECREMENT:
            return preState - data
        default:
            return preState
    }
}

store.js

import {createStore} from 'redux'
import countReducer from './count_reducer'

export default createStore(countReducer)

index.js

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

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<App/>);

store.subscribe(() => {
    root.render(<App/>);
})




6.异步action版

  • 明确:延迟的动作不想交给组件自身,想交给action
  • 何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
  • 具体编码:
    • yarn add redux-thunk,并配置在store中
    • 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
    • 异步任务有结果后,分发一个同步的action去真正操作数据。 
  • 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action

Count.jsx

import React, {Component} from 'react';
import store from '../../redux/store'
import {createIncrementAction, createDecrementAction, createIncrementAsyncAction} from '../../redux/count_action'

class Count extends Component {
    state = {carName: '奔驰c63'}

    // componentDidMount() {
    //     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))
        store.dispatch(createIncrementAsyncAction(value * 1, 500))
        // }, 500)
    }

    render() {
        return (
            <div>
                <h1>车名字:{this.state.carName}</h1>
                <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>
        );
    }
}

export default Count;

count_action.js

import {DECREMENT, INCREMENT} from "./constant";

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

//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(createIncrementAction(data))
        }, time)
    }
}

store.js

import {createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
import thunk from 'redux-thunk'

export default createStore(countReducer, applyMiddleware(thunk))

7.对react-redux的理解 

 

8.连接容器组件与UI组件,react-redux基本使用

  • 明确两个概念:
    • UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
    • 容器组件:负责和redux通信,将结果交给UT组件。
  • 如何创建一个容器组件-----靠react-redux 的connect函数
    • connect(mapStateToProps,mapDispatchToProps)(UI组件)
    • mapstateToProps:映射状态,返回值是一个对象
    • mapDispatchToProps:映射操作状态的方法,返回值是一个对象
  • 备注:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入 

components/Count/Count.jsx

import React, {Component} from 'react';

class Count extends Component {
    state = {carName: '奔驰c63'}

    increment = () => {
        const {value} = this.selectNumber
        this.props.add(value * 1)
    }

    decrement = () => {
        const {value} = this.selectNumber
        this.props.sub(value * 1)
    }

    incrementIfOdd = () => {
        const {value} = this.selectNumber
        if (this.props.count % 2 !== 0) {
            this.props.add(value * 1)
        }
    }

    incrementAsync = () => {
        const {value} = this.selectNumber
        this.props.addAsync(value * 1, 500)
    }

    render() {
        return (
            <div>
                <h1>车名字:{this.state.carName}</h1>
                <h1>当前求和为:{this.props.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>
        );
    }
}

export default Count;

 containers/Count/Count.jsx

import CountUI from '../../components/Count/Count'
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";
import {number} from "prop-types";

function mapStateToProps(state) {
    return {count: state}
}

function mapDispatchToProps(dispatch) {
    return {
        add: (number) => {
            dispatch(createIncrementAction(number))
        },
        sub: (number) => {
            dispatch(createDecrementAction(number))
        },
        addAsync: (number, time) => {
            dispatch(createIncrementAsyncAction(number, time))
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(CountUI)

constant.js

export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'

 count_action.js

import {DECREMENT, INCREMENT} from "./constant";

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

//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(createIncrementAction(data))
        }, time)
    }
}

count_reducer.js

import {INCREMENT, DECREMENT} from "./constant";

const initState = 0

export default function countReducer(preState = initState, action) {
    const {type, data} = action

    switch (type) {
        case INCREMENT:
            return preState + data
        case DECREMENT:
            return preState - data
        default:
            return preState
    }
}

store.js

import {createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
import thunk from 'redux-thunk'

export default createStore(countReducer, applyMiddleware(thunk))

App.js

import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import store from "./redux/store";

class App extends Component {
    render() {
        return (
            <div>
                <Count store={store}></Count>
            </div>
        );
    }
}

export default App;

index.js 

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

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<App/>);

store.subscribe(() => {
    root.render(<App/>);
})




9.优化1_简写mapDispatch

containers/Count/Count.jsx

import CountUI from '../../components/Count/Count'
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";


export default connect(
    state => ({count: state}),
    // (dispatch) => (
    //     {
    //         add: number => dispatch(createIncrementAction(number)),
    //         sub: number => dispatch(createDecrementAction(number)),
    //         addAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time))
    //
    //     })

    {
        add: createIncrementAction,
        sub: createDecrementAction,
        addAsync: createIncrementAsyncAction
    }
)(CountUI)

 10.优化2_Provider组件的使用

 App.js

import React, {Component} from 'react';
import Count from "./containers/Count/Count";

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

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
    <Provider store={store}>
        <App/>
    </Provider>
);

11.优化3_整合UI组件与容器组件

  • 容器组件和UI组件组合成一个文件
  • 无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
  • 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
  • mapDispatchToProps也可以简单的写成一个对象
  • 一个组件要和redux“打交道”要经过哪几步?
    • 定义好UI组件---不暴露
    • 引入connect生成一个容器组件,并暴露,写法如下:
    • connect(
    • state =>({key:value})
    • {key : xxxxxAction}
    • )(UI组件)
  • 在UI组件中通过this.props.xxxxxxx读取和操作状态

containers/Count/Count.jsx

import React, {Component} from 'react';
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";

class Count extends Component {
    state = {carName: '奔驰c63'}

    increment = () => {
        const {value} = this.selectNumber
        this.props.add(value * 1)
    }

    decrement = () => {
        const {value} = this.selectNumber
        this.props.sub(value * 1)
    }

    incrementIfOdd = () => {
        const {value} = this.selectNumber
        if (this.props.count % 2 !== 0) {
            this.props.add(value * 1)
        }
    }

    incrementAsync = () => {
        const {value} = this.selectNumber
        this.props.addAsync(value * 1, 500)
    }


    render() {
        console.log(this.props)
        return (
            <div>
                <h1>车名字:{this.state.carName}</h1>
                <h1>当前求和为:{this.props.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>
        );
    }
}


export default connect(
    state => ({count: state}),
    {
        add: createIncrementAction,
        sub: createDecrementAction,
        addAsync: createIncrementAsyncAction
    }
)(Count)

12.数据共享_编写Person组件,编写Person组件的reducer,完成数据共享

  • 定义一个Pserson组件,和Count组件通过redux共享数据
  • 为Person组件编写: reducer、action,配置constant常量。
  • 重点: Person的reducer和Count的Reducer要使用combineReducers进行合并,合并后的总状态是一个对象!! !
  • 交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。 

 index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
    <Provider store={store}>
        <App/>
    </Provider>
);

App.js

import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import Person from "./containers/Person/Person";

class App extends Component {
    render() {
        return (
            <div>
                <Count></Count>
                <hr></hr>
                <Person></Person>
            </div>
        );
    }
}

export default App;

 store.js

import {createStore, applyMiddleware, combineReducers} from 'redux'
import countReducer from './reducers/count'
import thunk from 'redux-thunk'
import personReducer from "./reducers/person";

const allReducer = combineReducers({
    he: countReducer,
    rens: personReducer
})

export default createStore(allReducer, applyMiddleware(thunk))

constant.js

export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

 reducers/person.js

import {ADD_PERSON} from "../constant";

const initState = [{id: '001', name: 'tom', age: 18}]

export default function personReducer(preState = initState, action) {
    const {type, data} = action
    switch (type) {
        case ADD_PERSON:
            return [data, ...preState]
        default:
            return preState;
    }
}

reducers/count.js

import {INCREMENT, DECREMENT} from "../constant";

const initState = 0

export default function countReducer(preState = initState, action) {
    const {type, data} = action

    switch (type) {
        case INCREMENT:
            return preState + data
        case DECREMENT:
            return preState - data
        default:
            return preState
    }
}

actions/person.js

import {ADD_PERSON} from '../constant'

export const createAddPersonAction = personObj => ({type: ADD_PERSON, data: personObj})

actions/count.js

import {DECREMENT, INCREMENT} from "../constant";

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

//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(createIncrementAction(data))
        }, time)
    }
}

 Person.jsx

import React, {Component} from 'react';
import {nanoid} from "nanoid";
import {connect} from "react-redux";
import {createAddPersonAction} from "../../redux/actions/person";

class Person extends Component {
    addPerson = () => {
        const name = this.nameNode.value
        const age = this.ageNode.value
        const personObj = {id: nanoid(), name, age}
        this.props.jiaYiRen(personObj)
        this.nameNode.value = ''
        this.ageNode.value = ''
    }

    render() {
        return (
            <div>
                <h2>我是person组件,上方组件求和为{this.props.he}</h2>
                <input ref={c => this.nameNode = c} type="text" placeholder="输入名字"/>&nbsp;
                <input ref={c => this.ageNode = c} type="text" placeholder="输入名字"/>&nbsp;
                <button onClick={this.addPerson}>添加</button>
                &nbsp;
                <ul>
                    {
                        this.props.yiduiren.map((p) => {
                            return <li key={p.id}>{p.name}--{p.age}</li>
                        })
                    }
                </ul>
            </div>
        );
    }
}

export default connect(
    state => ({yiduiren: state.rens, he: state.he}),
    {jiaYiRen: createAddPersonAction}
)(Person)

count.jsx

import React, {Component} from 'react';
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/actions/count";

class Count extends Component {

    increment = () => {
        const {value} = this.selectNumber
        this.props.add(value * 1)
    }

    decrement = () => {
        const {value} = this.selectNumber
        this.props.sub(value * 1)
    }

    incrementIfOdd = () => {
        const {value} = this.selectNumber
        if (this.props.count % 2 !== 0) {
            this.props.add(value * 1)
        }
    }

    incrementAsync = () => {
        const {value} = this.selectNumber
        this.props.addAsync(value * 1, 500)
    }


    render() {
        return (
            <div>
                <h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
                <h2>当前求和为:{this.props.count}</h2>
                <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>
        );
    }
}


export default connect(
    state => ({count: state.he, renshu: state.rens.length}),
    {
        add: createIncrementAction,
        sub: createDecrementAction,
        addAsync: createIncrementAsyncAction
    }
)(Count)

项目结构:

 运行结果:

13.纯函数

  • 一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)
  • 必须遵守以下一些约束
    • 不得改写参数数据
    • 不会产生任何副作用,例如网络请求,输入和输出设备
    • 不能调用Date.now)或者Math.random()等不纯的方法
  • redux的reducer函数必须是一个纯函数

14.高阶函数:

  • 理解:一类特别的函数
    • 情况1:参数是函数2
    • 情况2:返回是函数
  • 常见的高阶函数:
    • 定时器设置函数
    • 数组的forEach()/map(/filter(/reduce()/find0/bind()
    • promise

15.redux开发者工具 

  • yarn add redux-devtools-extension
  • store中进行配置
    • import {composewithDevTools} from 'redux-devtools-extension'
    • const store = createStore(allReducer,composelithDevTools(applyMiddleware(thunk)))

16. 最终版

  • 所有变量名字要规范,尽量触发对象的简写形式。
  • reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
    <Provider store={store}>
        <App/>
    </Provider>
);

 App.js

import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import Person from "./containers/Person/Person";

class App extends Component {
    render() {
        return (
            <div>
                <Count></Count>
                <hr></hr>
                <Person></Person>
            </div>
        );
    }
}

export default App;

store.js

import {createStore, applyMiddleware, combineReducers} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools} from "redux-devtools-extension";
import allReducer from "./reducers";


export default createStore(allReducer, composeWithDevTools(applyMiddleware(thunk)))

 constant.js

export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

reducers/count.js

import {INCREMENT, DECREMENT} from "../constant";

const initState = 0

export default function countReducer(preState = initState, action) {
    const {type, data} = action

    switch (type) {
        case INCREMENT:
            return preState + data
        case DECREMENT:
            return preState - data
        default:
            return preState
    }
}

 reducers/index.js

import {combineReducers} from "redux";
import countReducer from "./count";
import personReducer from "./person";


const allReducer = combineReducers({
    count: countReducer,
    persons: personReducer
})

export default allReducer

reducers/person.js

import {ADD_PERSON} from "../constant";

const initState = [{id: '001', name: 'tom', age: 18}]

export default function personReducer(preState = initState, action) {
    const {type, data} = action
    switch (type) {
        case ADD_PERSON:
            return [data, ...preState]
        default:
            return preState;
    }
}

 actions/count.js

import {DECREMENT, INCREMENT} from "../constant";

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

//异步action,就是指action的值为函数
export const incrementAsync = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(increment(data))
        }, time)
    }
}

actions/person.js

import {ADD_PERSON} from '../constant'

export const addPerson = personObj => ({type: ADD_PERSON, data: personObj})

 Person.jsx

import React, {Component} from 'react';
import {nanoid} from "nanoid";
import {connect} from "react-redux";
import {addPerson} from "../../redux/actions/person";

class Person extends Component {
    addPerson = () => {
        const name = this.nameNode.value
        const age = this.ageNode.value * 1
        const personObj = {id: nanoid(), name, age}
        this.props.addPerson(personObj)
        this.nameNode.value = ''
        this.ageNode.value = ''
    }

    render() {
        return (
            <div>
                <h2>我是person组件,上方组件求和为{this.props.count}</h2>
                <input ref={c => this.nameNode = c} type="text" placeholder="输入名字"/>&nbsp;
                <input ref={c => this.ageNode = c} type="text" placeholder="输入名字"/>&nbsp;
                <button onClick={this.addPerson}>添加</button>
                &nbsp;
                <ul>
                    {
                        this.props.persons.map((p) => {
                            return <li key={p.id}>{p.name}--{p.age}</li>
                        })
                    }
                </ul>
            </div>
        );
    }
}

export default connect(
    state => ({persons: state.persons, count: state.count}),
    {addPerson}
)(Person)

Count.jsx

import React, {Component} from 'react';
import {connect} from 'react-redux'
import {
    decrement,
    increment,
    incrementAsync
} from "../../redux/actions/count";

class Count extends Component {

    increment = () => {
        const {value} = this.selectNumber
        this.props.increment(value * 1)
    }

    decrement = () => {
        const {value} = this.selectNumber
        this.props.decrement(value * 1)
    }

    incrementIfOdd = () => {
        const {value} = this.selectNumber
        if (this.props.count % 2 !== 0) {
            this.props.increment(value * 1)
        }
    }

    incrementAsync = () => {
        const {value} = this.selectNumber
        this.props.incrementAsync(value * 1, 500)
    }


    render() {
        return (
            <div>
                <h2>我是Count组件,下方组件总人数为:{this.props.personCount}</h2>
                <h2>当前求和为:{this.props.count}</h2>
                <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>
        );
    }
}


export default connect(
    state => ({count: state.count, personCount: state.persons.length}),
    {
        increment,
        decrement,
        incrementAsync
    }
)(Count)

17.项目打包运行 

1.下载依赖

2.build 

3.启动服务器:

4.运行结果:

18.项目地址 

https://gitee.com/coderPatrickStar/react/tree/master/20231003

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1152201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

风云七剑攻略,最强阵容搭配

今天的风云七剑攻略最强阵容搭配给大家推荐以神仙斋减怒回血为主的阵容。 关注【娱乐天梯】&#xff0c;获取内部福利号 首先&#xff0c;这个角色在这个阵容当中&#xff0c;所有的角色当中&#xff0c;他的输出系数是最高的&#xff0c;已经达到了200%的层次&#xff0c;而且…

【NLP】什么是语义搜索以及如何实现 [Python、BERT、Elasticsearch]

语义搜索是一种先进的信息检索技术&#xff0c;旨在通过理解搜索查询和搜索内容的上下文和含义来提高搜索结果的准确性和相关性。与依赖于匹配特定单词或短语的传统基于关键字的搜索不同&#xff0c;语义搜索会考虑查询的意图、上下文和语义。 语义搜索在搜索结果的精度和相关…

Linux 文件系统之虚拟文件系统

文章目录 一、简介二、进程读写文件示例三、VFS高速缓存参考资料 一、简介 虚拟文件系统&#xff08;Virtual File System&#xff0c;简称 VFS&#xff09;是内核中的软件层&#xff0c;为用户空间程序提供文件系统接口。它还在内核中提供了一个抽象层&#xff0c;允许不同的…

SQL 通用数据类型

SQL 通用数据类型 数据类型定义了存储在列中的值的类型。 SQL 通用数据类型 数据库表中的每一列都需要有一个名称和数据类型。 SQL 开发人员必须在创建 SQL 表时决定表中的每个列将要存储的数据的类型。数据类型是一个标签&#xff0c;是便于 SQL 了解每个列期望存储什么类型的…

[GKCTF 2021]easycms 禅知cms

一道类似于渗透的题目 记录一下 首先扫描获取 登入界面 admin/12345登入 来到了后台 然后我们开始测试有无漏洞点 1.文件下载 设计 自定义 导出 然后进行抓包 解密后面的内容 发现是绝对路径了 所以这里我们要获取 flag 就/flag即可 L2ZsYWc /admin.php?mui&fdownlo…

linux的使用学习(1)

Linux 修改root密码 1.以 root 用户或具有 sudo 权限的登录到 Linux 系统。 2.打终端&#xff0c;并执行以下命令以更改 root 用户的密码&#xff1a; sudo passwd root 3.然后&#xff0c;系统会要求你输入新的 root 密码。请注意&#xff0c;在输入密码时&#xff0c;终端界…

图、深度优先(DFS)、广度优先(BFS)

图 基本介绍 表示方式 图的创建 from typing import Listclass Graph:vertex_list: List[str] [] # 存储顶点的数组edges: List[list] [] # 存储图中各条边的邻接矩阵num_edges: int 0 # 边的数总数def __init__(self, n: int):"""根据传入的顶点个数初始…

11、插件注入到vue实例中

新建插件 nuxt-demo2\plugins\vue-inject.js import Vue from "vue"Vue.prototype.$test function (str) {console.log(str) }配置插件 nuxt-demo2\nuxt.config.js export default {...// Plugins to run before rendering page: https://go.nuxtjs.dev/config-…

表格识别软件:科技革新引领行业先锋,颠覆性发展前景广阔

表格识别软件的兴起背景可以追溯到数字化和自动化处理的需求不断增加的时期。传统上&#xff0c;手动处理纸质表格是一项费时费力的工作&#xff0c;容易出现错误&#xff0c;效率低下。因此&#xff0c;开发出能够自动识别和提取表格数据的软件工具变得非常重要。 随着计算机…

Xcode运行程序提示 Executable Path is a Directory 问题解决

一、首先运行模拟器报错&#xff08;没有记录&#xff09;&#xff0c;解决办法&#xff1a; TARGET->Build Settings->Architectures -> Exclude Architectures里面填入arm64&#xff0c;后运行模拟器成功 二、其次模拟器开发完成后&#xff0c;xcode运行真机调试&…

canvas:理解canvas / 基础使用 / Demo效果

一、理解Canvas Canvas是一个HTML5元素&#xff0c;用于在Web页面上绘制2D或3D图形。它允许使用JavaScript在网页上创建和操作图形。Canvas的主要功能是绘图&#xff0c;但也可以用来实现其他功能&#xff0c;如动画和交互式游戏。 使用Canvas&#xff0c;可以创建各种形状、…

【AOP进阶】实现重试机制

&#x1f4da;目录 ⚙️简介&#xff1a;✨注解定义&#xff1a;⛳RetryMechanism ⌛编写AOP代码&#xff1a;⚓RetryMechanismAspect 切面 ⛵演示&#xff1a;⛴如何使用RetryMechanism&#xff1a;⚡️正常请求如下&#xff1a;☘️测试异常并且重试&#xff1a;☄️测试异常…

WSL2 Ubuntu安装CUDA Toolkit

目前CUDA ToolKit需要切换到WSL2&#xff0c;在WLS1下不支持。之前折腾了很久&#xff0c;才从WSL1的坑中爬出来&#xff0c;仅写此文避免大家再从坑里走一次。 Windows WSL2相关 检查正在运行的 WSL 版本 可列出已安装的 Linux 发行版&#xff0c;并通过在 PowerShell 或 W…

Android NDK开发详解之ndk-gdb

Android NDK开发详解之ndk-gdb 要求用法选项 线程支持 NDK 包含一个名为 ndk-gdb 的 Shell 脚本&#xff0c;可以启动命令行原生调试会话。偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档。 要求 要运行命令行原生调试&#xff0c;必须满足以下要求&#xff1…

SDK 消息处理

目录 消息处理 窗口通知消息处理 鼠标消息 键盘消息 绘图消息 WM_PAINT 客户区与非客户区 WM_PAINT消息 BeginPaint && EndPaint 模仿记事本输入字符功能 定时器 消息处理 窗口的过程函数接收到消息后并且进行处理。平时常用的消息以及官方参考文档&#xf…

“ 1+2+N “打造“北斗+智慧城市”,让城市生活更美好

10月31日是世界城市日。世界城市日是联合国首个以城市为主题的国际日&#xff0c;也是第一个由中国政府倡议并成功设立的国际日&#xff0c;出自2010年10月31日上海世博会高峰论坛上发布的《上海宣言》中的倡议。世界城市日秉承了中国2010年上海世博会“城市&#xff0c;让生活…

前端知识与基础应用#2

标签的分类 关于标签我们可以分为 &#xff1a; 单标签&#xff1a;img, br hr 双标签&#xff1a;a&#xff0c;h,div 按照属性可分为&#xff1a; 块儿标签&#xff08;自己独自占一行&#xff09;&#xff1a;h1-h6, p,div 行内&#xff08;内联&#xff09;标签&#xff08…

【1】C语言实现顺序表

文章目录 Ⅰ 概念及结构1. 静态顺序表2. 动态顺序表 Ⅱ 基本操作实现1. 定义顺序表2. 初始化顺序表3. 销毁顺序表4. 输出顺序表5. 扩容顺序表6. 尾插法插入数据7. 头插法插入数据8. 尾删法删除数据9. 头删法删除数据10. 顺序表查找11. 在指定位置 pos 插入数据12. 删除指定位置…

【算法】动态规划之LeetCode 53.最大子数组和

目录 文章目录 **目录**&#x1f4d1;前言1.题目描述2. 动态规划法 &#x1f4d1;文章末尾 &#x1f4d1;前言 本文主要是leetcode题解析&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁…

联想方案服务斩获CCF技术发明奖,助力云原生技术发展

10月27日&#xff0c;中国计算机学会&#xff08;CCF&#xff09;公布了我国计算机科技领域最具权威性的科技奖项——2023年度“CCF科技成果奖”评选结果&#xff0c;共有41个项目荣获2023年度CCF科技成果奖。由联想集团与上海交通大学等共同研究开发的《面向互联网服务的云原生…