解析react-redux官方案例todo

来源:互联网 发布:淘宝违规申诉入口 编辑:程序博客网 时间:2024/06/05 23:47

我相信很多小伙伴在学习react-redux都会涉及到一个todo的官方案例,不过刚刚开始接触的人可能看十几次都没感觉,现在我本人对它的总结下

一、项目的构建

  • 1、本项目我使用前端脚手架yeoman构建参考
  • 2、创建一个todo项目

    yo react-webpack
  • 3、安装别的依赖包

    npm install redux --savenpm install react-redux --savenpm install redux-thunk --save  
  • 4、把刚刚构建的项目运行

    npm run serve
  • 5、在浏览器上访问

    localhost:8000

二、运行后项目效果图

这里写图片描述

三、项目组件拆分

  • 1、上面输入框与添加按钮拆分为一个组件AddTodo
  • 2、中间显示的拆分一个组件TodoList
  • 3、底部分类拆分一个组件Link

四、todo项目的开发

  • 1、项目结构(关心我圈住的就可以)

    这里写图片描述

  • 2、根据redux构建项目的方式创建几个文件夹如不清楚请参考
  • 3、开发流程(一般开发流程)

    这里写图片描述

五、AddTodo组件的开发

  • 1、创建action(如果项目大,可以一个组件写一个action.js)

    /** * 定义todo项目的action */'use strict';let nextTodo = 0;// 一般外面需要使用的会定义常量export const ADD_TODO = 'ADD_TODO';export const TOGGLE_TODO = 'TOGGLE_TODO';// 定义一个添加的actionexport const addTodo = (text) => ({    type: ADD_TODO,    id: nextTodo++,    text});// 定义一个切换的actionexport const toggleTodo = (id) => ({    type: TOGGLE_TODO,    id})
  • 2、AddTodo组件的reducer的书写

    项目需要可以一个组件写一个reducer.js然后用combineReducers合并在一起

    import { combineReducers } from 'redux';import { ADD_TODO, TOGGLE_TODO} from './../actions/index';const todos = (state = [], action) => {    switch (action.type) {        case ADD_TODO:            return [                ...state,                {                    id: action.id,                    text: action.text,                    completed: false                }            ];        case TOGGLE_TODO:            // 定义切换的,如果当前点击的id等于传递进来的id就改变状态,否则就不边            return state.map(todo => {                if (todo.id === action.id) {                    return { ...todo, completed: !todo.completed }                } else {                    return todo;                }            })        default:            return state;    }}
  • 3、书写展示组件

    ...render() {    // console.log(this.props);    return (        <div>            <input type="text" placeholder="请输入内容" ref="myinput"/>            <input type="button" value="添加" onClick={this.addTodo} />        </div>    )}...
  • 4、容器组件(如果对块还有不清楚请参考)

    'use strict'/** * 定义AddTodo的容器组件 */import {connect} from 'react-redux';import AddTodo from './../components/AddTodo';// 这样全部的导入的就有点浪费,在AddTodo中只用了一个addTodo方法// import * as ActionCreators from './../actions/index';import {addTodo} from './../actions';export default connect(    state=>({todos:state.todos}),    // ActionCreators    dispatch =>({        addTodo:(text)=>dispatch(addTodo(text))    }))(AddTodo);
  • 5、容器组件传递了todosaddTodo到展示组件,再看展示组件的完整代码

    /** * AddTodo展示组件 */'use strict'import React, { Component } from 'react';export default class AddTodo extends Component {    constructor(props) {        super(props);        this.addTodo = this.addTodo.bind(this);    }    render() {        // console.log(this.props);        return (            <div>                <input type="text" placeholder="请输入内容" ref="myinput"/>                <input type="button" value="添加" onClick={this.addTodo} />            </div>        )    }    // 增加的todo的方法    addTodo() {        const { addTodo } = this.props;        // 获取到input的dom节点        let myinputDom = this.refs.myinput;        // 发送完成后就清空输入框        addTodo(myinputDom.value);        myinputDom.value = '';    }}// 约束数据类型AddTodo.protoTypes = {    addTodo: React.PropTypes.func.isRequired}
  • 6、组装到项目中试跑(本项目中创建了一个入口的App.js来统一管理)

    import 'core-js/fn/object/assign';import React from 'react';import ReactDOM from 'react-dom';import {createStore,applyMiddleware} from 'redux';import thunk from 'redux-thunk';import {Provider} from 'react-redux';import todoApp from './reducers/index';import App from './components/App';let store = createStore(todoApp,applyMiddleware(thunk));// Render the main component into the domReactDOM.render(    <Provider store={store}>        <App />    </Provider>, document.getElementById('app'));
    /** * 主文件入口 */'use strict'import React, { Component } from 'react';import AddTodoConnect from './../containers/AddTodoConnect';export default class App extends Component {    constructor(props){        super(props);    }    render() {        return (            <div>                <AddTodoConnect/>            </div>        )    }}

六、显示添加的todo组件

  • 1、展示组件(就是接受props数组便利出来)

    /** * todo的展示组件 */'use strict'import React, { Component } from 'react';// 引入样式require('styles/todolist.css');export default class TodoList extends Component {    constructor(props) {        super(props);    }    render() {        const { todos, toggleTodo } = this.props;        return (            <ul>                {                    todos.map(todo => (                        // 注意这个地方不能直接写onClik = {toggleTodo},这样的意思是立即执行                        //<li key={todo.id} onClick={()=>toggleTodo(todo.id)} style={{                        //textDecoration: todo.completed ? 'line-through' : 'none',                        //color: todo.completed ? 'red' : 'black'                        //}}>{todo.text}</li>                        <li key={todo.id} onClick={() => toggleTodo(todo.id)} className={todo.completed ? 'list-select' : 'list'}>{todo.text}</li>                    ))                }            </ul>        )    }}// 约束数据类型TodoList.protoTypes = {    todos: React.PropTypes.object.isRequired,    toggleTodo:React.PropTypes.func.isRequired}
  • 2、对应的容器组件

    /** * TodoList的容器组件 */'use strict'import { connect } from 'react-redux';import TodoList from './../components/TodoList';import { toggleTodo } from './../actions/index';export default connect(    state => ({ todos: state.todos}),    dispatch => ({        toggleTodo: (id) => dispatch(toggleTodo(id))    }))(TodoList);
  • 3、组装到App.js

七、底部的组件

  • 1、在action里面添加

    ...export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';export const SHOW_ALL = 'SHOW_ALL';// 定义一个是否显示的action,每次发送出去的的type是一样的export const setVisibilityFilter = (filter) => ({    type: SET_VISIBILITY_FILTER,    filter})
  • 2、在reducer里面添加

    // 定义一个底部选择的reducerconst visibilityFilter = (state = SHOW_ALL,action) => {    switch(action.type){        case SET_VISIBILITY_FILTER:            return action.filter        default:            return state    }}// 利用redux里面的combineReducers合并所有的reducerconst todoApp = combineReducers({    todos,    visibilityFilter})// 默认导出export default todoApp;
  • 3、定义展示组件

    /** * 定义一个底部现在的展示组件 */'use strict'import React, { Component } from 'react'// 引入样式require('styles/link.css');export default class Link extends Component {    constructor(props) {        super(props);    }    render() {        const { active, children, onClick } = this.props;        if (active) {            return <span>{children}</span>        } else {            return (                <a href="javascript:void(0)" onClick={()=>onClick()}>{children}</a>            )        }    }}
  • 4、定义容器组件(关于ownProps参考)

    /** * 定义Link的容器组件 */import { connect } from 'react-redux';import Link from './../components/Link.js';import { setVisibilityFilter } from './../actions/index';const mapStateToProps = function(state, ownProps){    console.log('ownProps--->',ownProps);    return {        active: ownProps.filter === state.visibilityFilter    }}const mapDispatchToProps = (dispatch, ownProps) => ({    onClick: () => {        dispatch(setVisibilityFilter(ownProps.filter))    }})/**下面这样也可以 * (state, ownProps) => ({        active: ownProps.filter === state.visibilityFilter    }),    (dispatch,ownProps) => ({        onClick: () => dispatch(setVisibilityFilter(ownProps.filter))    }) */export default connect(    mapStateToProps,    mapDispatchToProps)(Link);
  • 5、修改之前显示的todo组件(容器组件)

    ** * 定义一个过滤的方法 */const getVisibleTodos = (todos, filter) => {    switch(filter){        case 'SHOW_ALL':            return todos;        case 'SHOW_ACTIVE': //未完成            return todos.filter(todo => !todo.completed);        case 'SHOW_COMPLETED': // 已完成            return todos.filter(todo => todo.completed);        default:            return todos;    }}export default connect(    // 传递到展示组件的数据过滤了    state => ({ todos: getVisibleTodos(state.todos,state.visibilityFilter)}),    dispatch => ({        toggleTodo: (id) => dispatch(toggleTodo(id))    }))(TodoList);

八、demo下载地址

原创粉丝点击