【水滴石穿】mobx-todos

我以爲代碼在有些程序員手裏,就好像是畫筆,能夠創造不少東西
不要以爲創意少就叫沒有創意,天天進步一點點,世界更美好
首先源碼地址爲:https://github.com/byk04712/mobx-todos
感謝無私開源的程序員,是大家讓代碼更美好
先看效果

這個是一個todo的mobx小項目,咱們主要看看數據處理部分react

//根App.js文件中,主要是渲染組件main
//App.js
import React from 'react';
import {
    AppRegistry
} from 'react-native';
import Main from './Main';


AppRegistry.registerComponent('mobx_todos', () => Main);

在main.js中,咱們先來看佈局

git

這個裏面顯示了,實際上是將佈局分紅了上中下三部分程序員

class App extends Component {

    todoList = new TodoList();

    render() {
        return (
            <View style={styles.container}>
                <Header data={this.todoList}/>
                <ShowTodos data={this.todoList}/>
                <Filter data={this.todoList}/>
            </View>
        );
    }

}



export default App;

先看header部分代碼,看這個代碼寫的多美麗啊,這個仍是該做者2年前寫的呢~github

class Header extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    addItem = () => {
        const { data } = this.props;
        if (this.inputValue === undefined || this.inputValue.replace(/\s+/g, '') === '') {
            return alert('請輸入任務名稱');
        }
        data.addItem(this.inputValue);

        // clear input & reset input value
        this.input.clear();
        this.inputValue = '';
        //還處理了黃色預警
        Keyboard.dismiss();
    };

    render() {
        return (
            <View style={styles.header}>
                <TextInput
                    style={styles.input}
                    ref={input => this.input = input}
                    underlineColorAndroid='transparent'
                    placeholder='在此輸入新增的任務'
                    onChangeText={text => this.inputValue = text}
                    maxLength={10}
                />
                <TouchableOpacity onPress={this.addItem} style={styles.button}>
                    <Text style={styles.buttonText}>Add Todo</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

showtodos裏面卻是沒有什麼很特別的,不太重要的是裏面的小的組件,已經完成和未完成的,還有樣式的處理
react-native

class ShowTodos extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    renderRow = (data) => {
        return (<TodoItem data={data}/>)
    };

    render() {
        const { data } = this.props;
        return (
            <View style={styles.showTodos}>
                <ListView
                    style={styles.listView}
                    enableEmptySections
                    initialListSize={data.items.length}
                    dataSource={ds.cloneWithRows(data.items.slice())}
                    renderRow={this.renderRow}
                />
            </View>
        );
    }

}
@observer
class TodoItem extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(Todo)
    };

    render() {
        const { data } = this.props;
        //這個的處理有意思
        let flag;
        if (data.done) {
            flag = { textDecorationLine: 'line-through' };
        } else {
            flag = { textDecorationLine: 'none' };
        }
        return (
            <TouchableOpacity onPress={data.switchDone}>
                <View style={styles.item}>
                    <Text style={[styles.name, flag]} numberOfLines={1}>{data.name}</Text>
                    <Text style={[styles.done, flag]}>{data.done ? '已完成' : '未完成'}</Text>
                    <TouchableOpacity style={styles.del} onPress={data.remove}>
                        <Text style={styles.delText}>x</Text>
                    </TouchableOpacity>
                </View>
            </TouchableOpacity>
        );
    }
}
class Todo {

    id = `${Date.now()}${Math.floor(Math.random()*1000)}`;

    @observable
    name = '';

    @observable
    done = false;

    todos = null;

    constructor(name, done, todos) {
        this.name = name;
        this.done = done;
        this.todos = todos;
    }

    @action('任務 已完成/未完成 狀態切換')
    switchDone = () => {
        this.done = !this.done;
    };

    @action('刪除當前項')
    remove = () => {
        if (this.todos) {
            this.todos._items.remove(this);
        }
    }
}

這個是篩選部分
less

@observer
class Filter extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    render() {
        const { data } = this.props;
        return (
            <View style={styles.filter}>
                <Text>篩選:</Text>
                <FilterButton size={data.countAll} active={data.filter === ALL} onPress={data.filterAll}>所有</FilterButton>
                <FilterButton size={data.countCompleted} active={data.filter === COMPLETED} onPress={data.filterCompleted}>已完成</FilterButton>
                <FilterButton size={data.countUncompleted} active={data.filter === UNCOMPLETED} onPress={data.filterUncompleted}>未完成</FilterButton>
            </View>
        );
    }
}

看main.js中的所有代碼dom

import React,{
    Component,
    PropTypes
} from 'react';
import {
    TouchableOpacity,
    Dimensions,
    StyleSheet,
    TextInput,
    ListView,
    Keyboard,
    View,
    Text
} from 'react-native';
import {
    observable,
    computed,
    action,
    useStrict
} from 'mobx';
import {
    observer
} from 'mobx-react/native';


// 開啓嚴格模式,建議開啓。開啓後全部修改 observable 的操做都必須放在 action 裏完成
useStrict(true);


const { width, height } = Dimensions.get('window');
const contentWidth = width - 60;
const [ALL, COMPLETED, UNCOMPLETED] = ['ALL', 'COMPLETED', 'UNCOMPLETED'];
const ds = new ListView.DataSource({
    rowHasChanged: (r1, r2) => r1 !== r2
});


const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F7F7F7',
        alignItems: 'center',
        paddingVertical: 80
    },
    header: {
        width: contentWidth,
        height: 40,
        flexDirection: 'row',
        borderWidth: 1,
        borderColor: 'green'
    },
    input: {
        flex: 1,
        paddingHorizontal: 10
    },
    button: {
        width: 80,
        backgroundColor: 'green',
        justifyContent: 'center',
        alignItems: 'center'
    },
    buttonText: {
        color: 'white'
    },
    showTodos: {
        borderColor: 'green',
        borderLeftWidth: 1,
        borderRightWidth: 1,
        width: contentWidth,
        height: height - 300
    },
    listView: {
        paddingHorizontal: 10
    },
    item: {
        flexDirection: 'row',
        height: 50,
        borderBottomColor: '#CCC',
        borderBottomWidth: StyleSheet.hairlineWidth,
        justifyContent: 'space-between',
        alignItems: 'center',
    },
    name: {
        fontSize: 16,
        width: contentWidth - 90,
        overflow: 'hidden'
    },
    done: {
        fontSize: 12,
        color: 'gray'
    },
    del: {
        borderWidth: 1,
        borderColor: 'gray',
        width: 20,
        height: 20,
        borderRadius: 10
    },
    delText: {
        alignSelf: 'center'
    },
    filter: {
        width: contentWidth,
        height: 50,
        borderWidth: 1,
        borderColor: 'green',
        flexDirection: 'row',
        alignItems: 'center',
        paddingHorizontal: 5
    },
    condition: {
        paddingHorizontal: 5,
        paddingVertical: 7,
        marginHorizontal: 4,
        borderWidth: StyleSheet.hairlineWidth,
        borderColor: 'gray'
    },
    conditionText: {
        fontSize: 14,
        letterSpacing: 2
    }
});


class TodoList {

    @observable
    _items = [];

    @observable
    filter = ALL;

    // 初始化3條測試數據
    constructor() {
        this._items.push(new Todo('Travel', true, this));
        this._items.push(new Todo('Metting', false, this));
        this._items.push(new Todo('Conversation', true, this));
    }

    @computed
    get items() {
        return this._items.filter(item => {
            if (this.filter === ALL) {
                return item;
            } else if (this.filter === COMPLETED) {
                return item.done;
            } else if (this.filter === UNCOMPLETED) {
                return !item.done
            }
        });
    }

    @computed
    get countAll() {
        return this._items.length;
    }

    @computed
    get countCompleted() {
        return this._items.filter(item => item.done).length;
    }

    @computed
    get countUncompleted() {
        return this._items.filter(item => !item.done).length;
    }

    @action('添加任務')
    addItem = (name) => {
        if (name) {
            this._items.push(new Todo(name, false, this));
        }
    };

    @action('篩選所有')
    filterAll = () => {
        this.filter = ALL;
    };

    @action('篩選已完成的')
    filterCompleted = () => {
        this.filter = COMPLETED;
    };

    @action('篩選未完成的')
    filterUncompleted = () => {
        this.filter = UNCOMPLETED;
    }

}


class Todo {

    id = `${Date.now()}${Math.floor(Math.random()*1000)}`;

    @observable
    name = '';

    @observable
    done = false;

    todos = null;

    constructor(name, done, todos) {
        this.name = name;
        this.done = done;
        this.todos = todos;
    }

    @action('任務 已完成/未完成 狀態切換')
    switchDone = () => {
        this.done = !this.done;
    };

    @action('刪除當前項')
    remove = () => {
        if (this.todos) {
            this.todos._items.remove(this);
        }
    }
}


// Stateless Functional Component (無狀態的功能組件)
const FilterButton = function(props) {

    const { onPress, children, active, size } = props;

    let buttnStyle, buttonTextStyle;
    if (active) {
        buttnStyle = {backgroundColor: 'green'};
        buttonTextStyle = {color: 'white'};
    } else {
        buttnStyle = {backgroundColor: '#F7F7F7'};
        buttonTextStyle = {color: '#666'};
    }

    return (
        <TouchableOpacity onPress={onPress} disabled={active}>
            <View style={[styles.condition, buttnStyle]}>
                <Text style={[styles.conditionText, buttonTextStyle]}>{children}({size})</Text>
            </View>
        </TouchableOpacity>
    );
};


class Header extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    addItem = () => {
        const { data } = this.props;
        if (this.inputValue === undefined || this.inputValue.replace(/\s+/g, '') === '') {
            return alert('請輸入任務名稱');
        }
        data.addItem(this.inputValue);

        // clear input & reset input value
        this.input.clear();
        this.inputValue = '';
        //還處理了黃色預警
        Keyboard.dismiss();
    };

    render() {
        return (
            <View style={styles.header}>
                <TextInput
                    style={styles.input}
                    ref={input => this.input = input}
                    underlineColorAndroid='transparent'
                    placeholder='在此輸入新增的任務'
                    onChangeText={text => this.inputValue = text}
                    maxLength={10}
                />
                <TouchableOpacity onPress={this.addItem} style={styles.button}>
                    <Text style={styles.buttonText}>Add Todo</Text>
                </TouchableOpacity>
            </View>
        );
    }
}


@observer
class ShowTodos extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    renderRow = (data) => {
        return (<TodoItem data={data}/>)
    };

    render() {
        const { data } = this.props;
        return (
            <View style={styles.showTodos}>
                <ListView
                    style={styles.listView}
                    enableEmptySections
                    initialListSize={data.items.length}
                    dataSource={ds.cloneWithRows(data.items.slice())}
                    renderRow={this.renderRow}
                />
            </View>
        );
    }

}


@observer
class Filter extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(TodoList)
    };

    render() {
        const { data } = this.props;
        return (
            <View style={styles.filter}>
                <Text>篩選:</Text>
                <FilterButton size={data.countAll} active={data.filter === ALL} onPress={data.filterAll}>所有</FilterButton>
                <FilterButton size={data.countCompleted} active={data.filter === COMPLETED} onPress={data.filterCompleted}>已完成</FilterButton>
                <FilterButton size={data.countUncompleted} active={data.filter === UNCOMPLETED} onPress={data.filterUncompleted}>未完成</FilterButton>
            </View>
        );
    }
}


@observer
class TodoItem extends Component {

    static propTypes = {
        data: PropTypes.instanceOf(Todo)
    };

    render() {
        const { data } = this.props;
        //這個的處理有意思
        let flag;
        if (data.done) {
            flag = { textDecorationLine: 'line-through' };
        } else {
            flag = { textDecorationLine: 'none' };
        }
        return (
            <TouchableOpacity onPress={data.switchDone}>
                <View style={styles.item}>
                    <Text style={[styles.name, flag]} numberOfLines={1}>{data.name}</Text>
                    <Text style={[styles.done, flag]}>{data.done ? '已完成' : '未完成'}</Text>
                    <TouchableOpacity style={styles.del} onPress={data.remove}>
                        <Text style={styles.delText}>x</Text>
                    </TouchableOpacity>
                </View>
            </TouchableOpacity>
        );
    }
}


class App extends Component {

    todoList = new TodoList();

    render() {
        return (
            <View style={styles.container}>
                <Header data={this.todoList}/>
                <ShowTodos data={this.todoList}/>
                <Filter data={this.todoList}/>
            </View>
        );
    }

}



export default App;

是這個博客代碼寫的很好,仍是個人mobx不好啊,喜歡這個demo佈局

相關文章
相關標籤/搜索