一步一步學(xué)習(xí) ReactNative + Redux(3)

寫在開始

前篇中爱只,我們介紹了 Redux 画畅,對 Store 、 Action 渣锦、Reducer 有了初步的了解诚些。并配合 react-redux 飞傀,梳理了其工作流程皇型,結(jié)合使用了 Provider 、 connect() 砸烦。
接下來弃鸦,我們完成開篇任務(wù)中的最后一項,**過濾顯示 TODO **幢痘。

源碼:https://github.com/eylu/web-lib/tree/master/ReactReduxDemo/app_step3

開發(fā)

我們所做任務(wù)如下:

  • 在入口文件添加一個新的初始state:
    todos 平級唬格,做為當前過濾條件。
  • 創(chuàng)建一個子組件TodoFilterComponent
    包含3個過濾按鈕All颜说、Undo购岗、Finish,并接收一個屬性為當前過濾條件门粪,過濾按鈕與當前過濾條件相同時喊积,過濾按鈕不可點擊。
  • 修改容器組件HomeContainer
    引入過濾組件玄妈,并且可以設(shè)置當前過濾條件乾吻,根據(jù)過濾條件顯示不同狀態(tài)的 TODO 項。
  • 添加 Action
    定義ActionCreator生成設(shè)置當前過濾條件的 Action拟蜻。
  • 添加 Reducer:
    可以設(shè)置當前的過濾條件绎签。

1、添加新初始 state

ReactReduxDemo/app/index.js 文件瞭郑,修改如下:

import React, { Component } from 'react';
import {
    View,
    StyleSheet,
} from 'react-native';
import { createStore } from 'redux';        
import { Provider } from 'react-redux';     

import reducers from './reducers/index';    

import HomeContainer from './containers/home.container';

// 這是初始數(shù)據(jù)
const initState = {
    todos: [
        {title:'吃早飯',status:true},
        {title:'打籃球',status:false},
        {title:'修電腦',status:false},
    ],
    filter: 'All', // 'All'|'Undo'|'Finish'    // 添加新的初始 `state`
};

let store = createStore(reducers, initState);

export default class RootWrapper extends Component{
    render(){
        return (
            <Provider store={store}>
                <View style={styles.wrapper}>
                    <HomeContainer />
                </View>
            </Provider>
        );
    }
}

const styles = StyleSheet.create({
    wrapper: {
        flex: 1,
        marginTop: 20,
    },
});

2辜御、創(chuàng)建子組件 TodoFilterComponent

新建文件 ReactReduxDemo/app/components/todo-filter.component.js, 如下:

import React, { Component } from 'react';
import {
    View,
    Text,
    TouchableOpacity,
    StyleSheet,
} from 'react-native';


export default class TodoFilterComponent extends Component{
    constructor(props){
        super(props);
    }

    filterTodo(filter){
        this.props.filterTodo && this.props.filterTodo(filter);
    }

    renderFilter(filter){
        if(filter==this.props.filter){
            return (
                <Text style={[styles.filter,styles.filterCurrent]}>{filter}</Text>
            );
        }
        return (
            <TouchableOpacity onPress={()=>{this.filterTodo(filter)}}>
                <Text style={styles.filter}>{filter}</Text>
            </TouchableOpacity>
        );
    }

    render(){
        return (
            <View style={styles.wrapper}>
                {this.renderFilter('All')}
                {this.renderFilter('Undo')}
                {this.renderFilter('Finish')}
            </View>
        );
    }
}


const styles = StyleSheet.create({
    wrapper: {
        flexDirection: 'row',
        paddingLeft: 20,
        paddingTop: 20,
    },
    filter: {
        marginRight: 20,
        textDecorationLine: 'underline',
    },
    filterCurrent:{
        color: 'gray',
        textDecorationLine: 'none',
    },
});

3屈张、容器組件HomeContainer
我們在其中引入子組件TodoFilterComponent擒权,并添加過濾方法,此方法的功能為設(shè)置當前過濾條件阁谆。

ReactReduxDemo/app/containers/home.container.js 文件碳抄,修改如下:

import React, { Component } from 'react';
import {
    View,
    Text
} from 'react-native';
import { connect } from 'react-redux';

import { changeTodoStatus, addNewTodo, filterTodoList } from '../actions/index';  // 引入 action

import TodoFormComponent from '../components/todo-form.component';
import TodoListComponent from '../components/todo-list.component';
import TodoFilterComponent from '../components/todo-filter.component';            // 引入子組件

class HomeContainer extends Component{
    constructor(props){
        super(props);
    }

    addTodo(text){
        let { dispatch } = this.props;
        dispatch(addNewTodo(text));
    }

    toggleTodo(index){
        let { dispatch } = this.props;
        dispatch(changeTodoStatus(index));
    }

    filterTodo(filter){
        let { dispatch } = this.props;              // 從 props 里解構(gòu)出 dispatch
        dispatch(filterTodoList(filter));           // 執(zhí)行過濾方法
    }

    render(){
        return (
            <View>
                <TodoFormComponent addTodo={(text)=>{this.addTodo(text)}} />
                <TodoListComponent todoList={this.props.todoList} toggleTodo={(index)=>{this.toggleTodo(index)}} />
                <TodoFilterComponent filter={this.props.currentFilter} filterTodo={(filter)=>{this.filterTodo(filter)}} />  // 渲染子組件(注釋會報錯,請刪除注釋)
            </View>
        );
    }
}


// 基于全局 state 场绿,哪些 state 是我們想注入的 props
function mapStateToProps(state){
    return {
        todoList: state.todos,
        currentFilter: state.filter,               // 注入新的 state 到 props
    }
}

export default connect(mapStateToProps)(HomeContainer);

4剖效、修改 Action
添加新的 action 類型,新的 action 創(chuàng)建函數(shù)焰盗。
ReactReduxDemo/app/actions/index.js 文件璧尸,修改如下:

/*********************************** action 類型常量 *************************************/

/**
 * 更改 TODO 狀態(tài)
 * @type {String}
 */
export const TOGGLE_TODO_STATUS = 'TOGGLE_TODO_STATUS';

export const ADD_NEW_TODO = 'ADD_NEW_TODO';

export const SET_FILTER = 'SET_FILTER';         // 添加新的 action 類型

/*********************************** action 創(chuàng)建函數(shù) *************************************/

/**
 * 更改 TODO 狀態(tài)
 * @param  {Number} index TODO索引
 * @return {Object}       action
 */
export function changeTodoStatus(index){
    return {type: TOGGLE_TODO_STATUS, index};
}

export function addNewTodo(text){
    return {type: ADD_NEW_TODO, text};
}

export function filterTodoList(filter){      // 添加新的 action 創(chuàng)建函數(shù)
    return {type: SET_FILTER, filter};
};

5、修改 Reducer

引用新的action類型熬拒,添加新的reducer函數(shù)爷光,并在 combineReducers 中使用。

ReactReduxDemo/app/reducers/index.js文件澎粟,修改如下:

import { combineReducers } from 'redux';

import { TOGGLE_TODO_STATUS, ADD_NEW_TODO, SET_FILTER } from '../actions/index';    // 引入 action 蛀序,使用 action 類型常量


function todoList(state=[], action){
    switch(action.type){
        case TOGGLE_TODO_STATUS:
            var todo = state[action.index];
            return [
                ...state.slice(0, action.index),
                Object.assign({}, todo, {
                  status: !todo.status
                }),
                ...state.slice(action.index + 1)
            ];
        case ADD_NEW_TODO:
            return [
                ...state,
                {
                    title: action.text,
                    status: false,
                }
            ];
        default :
            return state;
    }

}

function setFilter(state='', action){       // 定義了新的 reducer
    switch(action.type){
        case SET_FILTER:
            return action.filter;
        default :
            return state;
    }
}

const reducers = combineReducers({
    todos: todoList,
    filter: setFilter,                      // 添加了新的 reducer combine
});

export default reducers;

運行項目欢瞪,是否顯示出了過濾按鈕呢?點擊試試看徐裸,能否過濾遣鼓?(暫時還不可以,我們需要寫方法對數(shù)據(jù)進行過濾)

Paste_Image.png

過濾 TODO 顯示

todo 列表有了重贺,當前過濾條件也可以設(shè)置了骑祟。這里,我們需要完成根據(jù)當前過濾條件對 TODO 列表進行過濾顯示檬姥。

我們知道曾我,TODO 列表的顯示,是根據(jù)容器組件HomeContainer給的數(shù)據(jù)來顯示的健民,它并不知道數(shù)據(jù)的具體來源抒巢,給它什么數(shù)據(jù)它就顯示什么數(shù)據(jù)(這也正是我們想要的功能)。

我們就會想到秉犹,將容器組件HomeContainer的 TODO 列表數(shù)據(jù)做修改蛉谜,是不是就可以了呢?是的崇堵,確實是這樣型诚。
我們來看容器組件HomeContainer部分代碼

// 基于全局 state ,哪些 state 是我們想注入的 props
function mapStateToProps(state){
    return {
        todoList: state.todos,        // <---- 這里就是給子組件展示的數(shù)據(jù)
        currentFilter: state.filter,
    }
}

我們將其做一些修改過濾鸳劳,就OK了狰贯。

ReactReduxDemo/app/containers/home.container.js文件,修改如下:

import React, { Component } from 'react';
import {
    View,
    Text
} from 'react-native';
import { connect } from 'react-redux';

import { changeTodoStatus, addNewTodo, filterTodoList } from '../actions/index';  

import TodoFormComponent from '../components/todo-form.component';
import TodoListComponent from '../components/todo-list.component';
import TodoFilterComponent from '../components/todo-filter.component';            

class HomeContainer extends Component{
    constructor(props){
        super(props);
    }

    addTodo(text){
        let { dispatch } = this.props;
        dispatch(addNewTodo(text));
    }

    toggleTodo(index){
        let { dispatch } = this.props;
        dispatch(changeTodoStatus(index));
    }

    filterTodo(filter){
        let { dispatch } = this.props;
        dispatch(filterTodoList(filter));
    }

    render(){
        return (
            <View>
                <TodoFormComponent addTodo={(text)=>{this.addTodo(text)}} />
                <TodoListComponent todoList={this.props.todoList} toggleTodo={(index)=>{this.toggleTodo(index)}} />
                <TodoFilterComponent filter={this.props.currentFilter} filterTodo={(filter)=>{this.filterTodo(filter)}} />
            </View>
        );
    }
}

const getFilterTodos = (todos, filter) => {               // 定義 TODO 過濾方法赏廓,返回新的數(shù)據(jù)
  switch (filter) {
    case 'All':
      return todos;
    case 'Undo':
      return todos.filter( todo => !todo.status);
    case 'Finish':
      return todos.filter( todo => todo.status);
    default:
      throw new Error('Unknown filter: ' + filter);
  }
}

// 基于全局 state 涵紊,哪些 state 是我們想注入的 props
function mapStateToProps(state){
    return {
        todoList: getFilterTodos(state.todos, state.filter),    // 注入props時,調(diào)用 TODO 過濾方法
        currentFilter: state.filter,
    }
}

export default connect(mapStateToProps)(HomeContainer);

運行項目幔摸,是否可以對 TODO 列表進行過濾了呢摸柄?恭喜你!既忆!

Undo狀態(tài)的TODO.png
Finish狀態(tài)的TODO.png

到目前為止驱负,我們的 ReactNative + Redux 開發(fā)示例告一小段落。
后面會有中間件患雇、異步的的使用方法跃脊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市苛吱,隨后出現(xiàn)的幾起案子匾乓,更是在濱河造成了極大的恐慌,老刑警劉巖又谋,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拼缝,死亡現(xiàn)場離奇詭異,居然都是意外死亡彰亥,警方通過查閱死者的電腦和手機咧七,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來任斋,“玉大人继阻,你說我怎么就攤上這事》峡幔” “怎么了瘟檩?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長澈蟆。 經(jīng)常有香客問我墨辛,道長,這世上最難降的妖魔是什么趴俘? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任睹簇,我火速辦了婚禮,結(jié)果婚禮上寥闪,老公的妹妹穿的比我還像新娘太惠。我一直安慰自己,他們只是感情好疲憋,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布凿渊。 她就那樣靜靜地躺著,像睡著了一般缚柳。 火紅的嫁衣襯著肌膚如雪埃脏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天喂击,我揣著相機與錄音剂癌,去河邊找鬼。 笑死翰绊,一個胖子當著我的面吹牛佩谷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播监嗜,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼谐檀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裁奇?” 一聲冷哼從身側(cè)響起桐猬,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刽肠,沒想到半個月后溃肪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體免胃,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年惫撰,在試婚紗的時候發(fā)現(xiàn)自己被綠了羔沙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡厨钻,死狀恐怖扼雏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夯膀,我是刑警寧澤诗充,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站诱建,受9級特大地震影響蝴蜓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涂佃,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一励翼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辜荠,春花似錦汽抚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至午笛,卻和暖如春惭蟋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背药磺。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工告组, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人癌佩。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓木缝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親围辙。 傳聞我的和親對象是個殘疾皇子我碟,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容