Easy的Redux學習筆記

1_開發環境搭建

1.1創建項目並編寫基礎代碼

安裝node.js、腳手架create-react-app等步驟詳見:Easy的React學習筆記(一.基礎),不再贅述。

在命令提示符(管理員)中,用腳手架create-react-app創建項目:

D:\Easy's code\ReduxDemo>create-react-app demo01

創建好惡demo01目錄如下,把src目錄內文件全刪了,重新創建index.js、TodoList.js。

分別修改index.js、TodoList.js的代碼。

index.js:

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

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

TodoList.js(可以用rcc快速生成,前提是安裝了React快速生成代碼插件Simple React Snippets):

import React, { Component } from 'react';

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

export default TodoList;

注:React快速生成代碼插件Simple React Snippets的安裝與使用

1.2安裝Ant Design

網絡慢的建議用cnpm

cnpm install antd --save

報錯:

peerDependencies WARNING [email protected] › rc-picker@~1.4.16 requires a peer of dayjs@^1.8.18 but none was installed

其實是缺少依賴的問題(這類缺少依賴的問題的詳細解決方法見:https://blog.csdn.net/qq_37279880/article/details/106180838

加上:

cnpm install dayjs@^1.8.18 --save

爲何要加--save這樣安裝?

因爲--save這種寫法可以添加依賴,詳見博文:  npm install的4種常用方式的區別(附表格對比)

 再試次一:

cnpm install antd --save

安裝成功:


2_用AntDesign製作UI界面

TodoList.js引入AntDesign的css樣式:

import 'antd/dist/antd.css'

引入要用的組件:

import {Input,Button,List} from 'antd'

引入要用的icon:

import { UserOutlined } from '@ant-design/icons';

用vscode的話可以安裝auto import插件,在引入過一次這個組件之後,第二次在另一個個文件引入就會有自動引入提示了:

vscode 自動導入包(組件)插件Auto Import安裝好後,依舊沒有自導導入提示的原因

編寫input框、button按鈕:

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { UserOutlined } from '@ant-design/icons';
import {Input,Button,List} from 'antd'

class TodoList extends Component {
    render() {
        return (
            <div style={{margin:'10px'}}>
                <div>
                     <Input placeholder='xxx'  style={{width:'233px', marginRight:'10px'}} prefix={<UserOutlined />} />
                     <Button type="primary">增加</Button>
                </div>
            </div>
        );
    }
}

export default TodoList;

加入List列表後,完整代碼如下:

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { UserOutlined } from '@ant-design/icons';
import {Input,Button,List} from 'antd'

const data = [
    '寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb',
    '奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb',
    '奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb'
]
class TodoList extends Component {
    render() {
        return (
            <div style={{margin:'10px'}}>
                <div>
                     <Input placeholder='xxx'  style={{width:'233px', marginRight:'10px'}} prefix={<UserOutlined />} />
                     <Button type="primary">增加</Button>
                </div>
                <div style={{margin:'10px',width:'300px'}}>
                    <List
                        bordered
                        dataSource={data}
                        renderItem={item=>(<List.Item>{item}</List.Item>)}
                    />
                </div>
            </div>
        );
    }
}

export default TodoList;

3_創建Redux中的倉庫:Store、Reducers

 Redux Flow圖:

Redux工作流程中有四個部分,最重要的就是store這個部分,因爲它把所有的數據都放到了store中進行管理。

在項目目錄安裝Redux:

npm install --save redux

安裝好redux之後,在src目錄下創建一個store並在文件夾下創建index.js,index.js就是整個項目的store文件,

store/index.js:

import {createStore} from 'redux' // 引入createStore方法
const store = reactStore()   // 創建數據存儲倉庫
export default store    //暴露出去

這樣雖然已經建立好了倉庫,但是這個倉庫很混亂,這時候就需要一個有管理能力的模塊出現,這就是Reducers。這兩個一定要一起

創建出來,這樣倉庫纔不會出現互懟現象。在store文件夾下,新建一個文件reducer.js。

store/reducer.js:

const defaultState = {} //默認數據
export default (state = defaultState,action)=>{ //就是一個方法函數
    return state
}

state: 是整個項目中需要管理的數據信息,這裏我們沒有什麼數據,所以用空對象來表示。

把reducer引入到store中,創建store時,reduce以參數的形式傳遞給store,

修改store/index.js:

import {createStore} from 'redux' // 引入createStore方法
import reducer from './reducer'

const store = reactStore(reducer)   // 創建數據存儲倉庫
export default store    //暴露出去

倉庫store和reducer都創建好了,可以初始化一下todoList中的數據了。在reducer.js文件的defaultState對象中,加入兩個屬

性:inputValue和list,這就相當於你給Store裏增加了兩個新的數據。

store/reducer.js

const defaultState = {
    inputValue:'寫點東西',
    list:[
        '寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb',
        '奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb',
        '奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb'
    ]
} //默認數據
export default (state = defaultState)=>{ //就是一個方法函數
    return state
}

TodoList.js引入store中的數據:

import store from './store/index'

 引入store後可以試着在構造方法裏打印到控制檯一下,看看是否真正獲得了數據,如果正常,是可以輸出store中的數據的:

constructor(props) {
    super(props);
    console.log(store.getState())
}

正常輸出store中數據:

測試數據正常後,直接讓this.state=store.getState(),把store的數據給TodoList,就可以把Input組件的placeholder、List的dataSource換成store的數據了。

修改TodoList.js

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { UserOutlined } from '@ant-design/icons';
import {Input,Button,List} from 'antd'
import store from './store/index'

class TodoList extends Component {
    constructor(props) {
        super(props);
        this.state=store.getState()
        // console.log(store.getState())
    }
    
    render() {
        return (
            <div style={{margin:'10px'}}>
                <div>
                     <Input placeholder={this.state.inputValue}  style={{width:'233px', marginRight:'10px'}} prefix={<UserOutlined />} />
                     <Button type="primary">增加</Button>
                </div>
                <div style={{margin:'10px',width:'300px'}}>
                    <List
                        bordered
                        dataSource={this.state.list}
                        renderItem={item=>(<List.Item>{item}</List.Item>)}
                    />
                </div>
            </div>
        );
    }
}

export default TodoList;

通過上面的步驟,實現了創建store、reduce和如何使用store中的數據。

4_Redux devtools插件的安裝與配置

4.1在chrome網上應用店搜索並安裝。不翻牆上chrome網上應用店的方法

4.2配置Redux devtools

直接在Redux devtools的github上覆制下面那段話到store/index.js中:

import {createStore} from 'redux' // 引入createStore方法
import reducer from './reducer'       //引入管理模塊reducer

const store = createStore(
    reducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    )   // 創建數據存儲倉庫
export default store    //暴露出去

配置好的效果:

5_通過Input組件體驗Redux流程

我們要實現的是在TodoList.js中文本框的值改變的話,reduxstore的值就跟着改變,並且如果Redux中的state值改變,組件也跟着改變。即如下圖的流程:

5.1爲Input組件綁定onChange事件

如果想Input改變,redux也跟着改變,需要在Input組件上增加onChange響應事件(TodoList.js):

<Input 
placeholder={this.state.inputValue}  
style={{width:'233px', marginRight:'10px'}} 
prefix={<UserOutlined />} 
onChange={this.changeInputValue}
/>

構造函數綁定onChange事件的this指向(TodoList.js):

constructor(props) {
    super(props);
    this.state=store.getState()
    // console.log(store.getState())
    this.changeInputValue=this.changeInputValue.bind(this)
}

render下方寫changeInputValue方法(TodoList.js):

changeInputValue(e){
    console.log(e.target.value)
}

注:onchange 事件會在域的內容改變時發生。

onChange綁定成功:

TodoList.js(完整代碼):

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { UserOutlined } from '@ant-design/icons';
import {Input,Button,List} from 'antd'
import store from './store/index'

class TodoList extends Component {
    constructor(props) {
        super(props);
        this.state=store.getState()
        // console.log(store.getState())
        this.changeInputValue=this.changeInputValue.bind(this)
    }
    
    render() {
        return (
            <div style={{margin:'10px'}}>
                <div>
                    <Input 
                    placeholder={this.state.inputValue}  
                    style={{width:'233px', marginRight:'10px'}} 
                    prefix={<UserOutlined />} 
                    onChange={this.changeInputValue}
                    />
                     <Button type="primary">增加</Button>
                </div>
                <div style={{margin:'10px',width:'300px'}}>
                    <List
                        bordered
                        dataSource={this.state.list}
                        renderItem={item=>(<List.Item>{item}</List.Item>)}
                    />
                </div>
            </div>
        );
    }
    changeInputValue(e){
        // console.log(e.target.value)
        const action = {
            type:'change_input_value',
            value:e.target.value
        }
        store.dispatch(action)
    }
}

export default TodoList;

5.2創建Action

想改變Redux的State值,就要創建Action。

Action就是一個對象,這個對象一般有兩個屬性,第一個是對Action的描述,第二個是要改變的值。

action創建之後,通過dispatch()方法傳遞給store。

修改changeInputValue方法(TodoList.js):

changeInputValue(e){
    // console.log(e.target.value)
    const action = {
        type:'changeInput',
        value:e.target.value
    }
    store.dispatch(action)
}

這是Action就已經完全創建完成了,也和store有了聯繫。

注;store.dispatch:分發 action。這是觸發 state 變化的惟一途徑。

5.3store自動推送策略

store只是一個倉庫,它並沒有管理能力,它會把接收到的action自動轉發給Reducer。直接在Reducer中打印出結果看一下。

修改store/reducer.js:

const defaultState = {
    inputValue:'寫點東西',
    list:[
        '寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb寶馬nb',
        '奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb奧迪nb',
        '奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb奔馳nb'
    ]
} //默認數據
export default (state = defaultState,action)=>{ //就是一個方法函數
        console.log(state,action)
        return state
}

state: 原始倉庫裏的狀態。

action: action新傳遞的狀態。

通過打印知道,Reducer已經拿到了原來的數據state和新傳遞過來的數據action,現在要改變store的值。我們先判斷type是不是正確的,如果正確,我們需要重新聲明一個變量newState。(注意:Reducer裏只能接收state,不能改變state。),所以我們聲明瞭一個新變量,然後再用return返回回去。

export default (state = defaultState,action)=>{ //就是一個方法函數
        console.log(state,action)
        if(action.type==='changeInput'){
            let newState =JSON.parse(JSON.stringify(state))////深度拷貝state
            newState.inputValue = action.value
            return newState
        }
        return state
}

注:

JavaScript JSON.parse():用於將一個 JSON 字符串轉換爲對象

JSON.stringify():將 JavaScript 對象轉換爲字符串

let cloneObj=JSON.parse(JSON.stringify(obj)):深拷貝最簡單的固定寫法

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章