react基础04--redux 管理数据

1 介绍

react基础03–render渲染、组件生命周期、组件通信 中介绍了React render渲染、组件生命周期、组件通信等重要知识。本文在其基础上继续介绍 redux 数据管理的方法,并配以实际案例。

实际项目中,很多时候需要在多个组件或者多个页面显示统一个数据,例如商品数量,如果通过参数传递就显得很麻烦。此时我们就可以通过redux事项数据管理。

2 方法&案例

安装 redux 模块:
npm i redux --save
安装后在 package.json 中就可以看到 { “dependencies”: {“redux”: “^4.1.2”}}

在多个组件中使用Store中的数据

  1. 定义Store.js 文件,引用 createStore函数,返回 createStore 的回调
  2. 在哪里使用就在哪里调用,分别在 App.js 和 Demo.js 中通过 Store.getState().name 访问Store中的数据即可,不需要各种复杂的传参步骤

vim index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>React App 2-1</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

vim index.js

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

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

vim Demo.js

import React, { Component } from 'react'
import App from './App';
import Store from './Store';

export default class Demo extends Component {
    constructor(){
        super();
        this.state = {
            msg: Store.getState().name
        }
    }
    render() {
        return (
            <div>
                <h1>this demo's Component, msg={this.state.msg}</h1>
                <App />
            </div>
        )
    }
}
export default Demo

vim App.js

import React, { Component } from 'react'
import Store from './Store'

export class App extends Component {
    constructor(){
        super()

        this.state = {
            name: Store.getState().name
        }
    }
    render() {
        return (
            <div>
                this App is: {this.state.name}
            </div>
        )
    }
}
export default App

vim Store.js

import { createStore } from 'redux'

const defaultState = {
    name: 'tom'
}
const store = createStore((state = defaultState,action)=>{
    return state;
    }
);
export default store

结果:
在这里插入图片描述

规范 store 写法

当需要存储的数据较多的时候,如果将所有的数据都放在 Store.js, 那么将会很冗余,因此需要将其拆分出为一个单独的 reducer.js
vim App.js

import React, { Component } from 'react'
import Store from './Store'
import Header from './Header'
import Content from './Content'
import Footer from './Footer'

export class App extends Component {
    constructor(){
        super()
        this.state = Store.getState()
    }
    render() {
        return (
            <div>
                <h2> App.js: {this.state.name} </h2>
                list: {this.state.list}
                <Header />
                <Content />
                <Footer />
            </div>
        )
    }
}
export default App

vim reducer.js

const defaultState = {
    name: 'tom',
    list: [1,2,3,4,5]
}

export default ((state = defaultState,action)=>{
    return state;
    }
);

vim Store.js

import { createStore } from 'redux'
import reducer from './reducer';

const store = createStore(reducer);
export default store

结果:
在这里插入图片描述

修改Store中的数据

当前端有操作的时候,可以捕获事件,在事件中将具体信息分发给reducer;
在reducer 中需要通过 action.type 来确认是哪个组件派发的,并将数据返回;
同时需要在组件中新增Store.subscribe函数,当其检测到更新就将数据更新到组件中;

vim reducer.js

const defaultState = {
    name: 'tom',
    list: [1,2,3,4,5]
}

export default (state = defaultState,action)=>{
    if (action.type === 'change_name'){
        let tmpState = state;
        tmpState.name = action.name;
        return tmpState
    }
    return state
};

vim Content.js

import React, { Component } from 'react'
import Store from './Store'

export class Content extends Component {
    constructor(){
        super()
        this.state = Store.getState()

        Store.subscribe(()=>{
            console.log(Store.getState());
            this.setState(Store.getState())
        })
    }    
    render() {
        return (
            <div>
                内容 {this.state.name} 
                <p>
                    <input input={this.state.name} onChange={this.change.bind(this)}/>
                    <button>提交</button>
                </p>
            </div>
        )
    }
    change(e){
        let inputValue = e.target.value;
        console.log(inputValue)
        let action = {
            type: 'change_name',
            name: inputValue
        }
        Store.dispatch(action) // 把action 对象派发给reducer
    }
}
export default Content

输出结果:
默认为 tom
在这里插入图片描述
输入bob后更新为bob
在这里插入图片描述

注意:
如果只在change(e)事件中使用 this.setState, 那么只会更新 Content 组件。

        this.setState({
            name: inputValue
        })

如果需要其它组件也更新相关字段,那么需要在其它组件中添加 Store.subscribe 函数。

refs属性获取元素对象

修改Store中的数据 中, 每次input中有变动就更新给各个组件,有时候需要输入完毕,点击提交的时候才将信息更新给不同的组件。
此时我们需要设置button 的onClick 事件,并且通过 input 的refs 获取元素的对象,并将该元素的值派发给reducer。

vim Content.js

import React, { Component } from 'react'
import Store from './Store'

export class Content extends Component {
    constructor(){
        super()
        this.state = Store.getState()

        Store.subscribe(()=>{
            this.setState(Store.getState())
        })
    }    
    render() {
        return (
            <div>
                内容 {this.state.name} 
                <p>
                    <input ref="inputValue"/>
                    <button onClick={this.click.bind(this)}>提交</button>
                </p>
            </div>
        )
    }
    click(){
        let inputValue = this.refs.inputValue.value;
        console.log(inputValue)
        let action = {
            type: 'change_name',
            name: inputValue
        }
        Store.dispatch(action) // 把action 对象派发给reducer
    }
}
export default Content

redux-thunk 中间件

安装组件

npm i axios --save
npm i redux-thunk --save

以上都是通过派发变量的方式改变参数,如果想派发函数,那么就需要redux-thunk中间件了。
需要在Store.js 中 createStore 引入 pplyMiddleware(thunk) 参数,在reducer.js 中引入对应的处理方法;
程序启动的时候将getList函数派发给thunk;
thunk 再将对应的数据派发给 reducer;
当 App 中的模块监听到 reducer的变动后,就会更新对应的数据。

vim data.json

{
    "list": [5,6,7,8,9]
}

vim reducer.js

const defaultState = {
    name: 'tom',
    list: [1,2,3,4,5]
}

export default (state = defaultState,action)=>{
    if (action.type === 'change_name'){
        let tmpState = state;
        tmpState.name = action.name;
        return tmpState;
    }
    // 初始化list
    if (action.type === 'init_list'){
        console.log(action);
        let tmpState = state;
        tmpState.list = action.list;
        return tmpState;
    }
    return state
};

vim Store.js

import { createStore, applyMiddleware } from 'redux'
import reducer from './reducer';
import thunk from 'redux-thunk'

const store = createStore(reducer, applyMiddleware(thunk));
export default store

vim App.js

import React, { Component } from 'react'
import Store from './Store'
import Header from './Header'
import Content from './Content'
import Footer from './Footer'
import axios from 'axios'

export class App extends Component {
    constructor(){
        super()
        this.state = Store.getState()
        Store.subscribe(()=>{
            this.setState(Store.getState())
        })
    }
    componentDidMount(){
        Store.dispatch(this.getList()) // 先派发给thunk
    }
    getList(){
        return (dispatch)=>{
            axios.get("http://localhost:3000/data.json")
            .then((resp)=>{
                // console.log(resp.data)
                let action = {
                    type: 'init_list',
                    list: resp.data.list
                }
                dispatch(action) //派发给reducer
            })
        }
    }
    render() {
        return (
            <div>
                <h2> App.js: {this.state.name} </h2>
                list: {this.state.list}
                <Header />
                <Content />
                <Footer />
            </div>
        )
    }
}
export default App

启动输出:
在这里插入图片描述

3 注意事项

  1. 如果只是分发不同变量,直接用普通的reducer即可;如果需要分发函数,那么需要使用 redux-thunk 组件来实现。

4 说明

软件版本:
node 16.13.1
create-react-app 5.0.0
参考文档:
React基础入门+综合案例
react 官网
React基础入门教程
中国 NPM 镜像

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昕光xg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值