• 【重点突破】—— Redux基础&进阶:用好Redux必备(一)


    前言:正在学习react大众点评项目课程的todoList应用阶段,学习react、redux、react-router基础知识。


    一、Redux基础

    1.Why Redux

    • 复杂的状态:API数据、本地数据、UI状态等
    • 视图和状态管理耦合,状态管理失控
    • 视图层:React状态管理层:Redux

      

    2.state

    • 集中管理,全局唯一
    • 不可变性
    • 定义方式同React State

    3.Actions

    • 描述如何修改状态
    • JSON对象,type属性必需
    • 发送:store.dispatch

    4.Reducer

    5.Reducer拆分

    • 便于维护和扩展
    • 合并API: combineReducers

    6.Store

    7.react-redux

    • 向根组件注入Store -> Provider组件
    • 连接React组件和Redux状态层 -> connect
    • 获取React组件所需的State和Actions -> map api(mapStateToProps,mapDispatchToProps

    8.展示型组件和容器型组件

    9.容器型编写

    • 本质上是react的高阶组件
      //AddTodoContainer.js
      import { connect } from "react-redux";
      import { setTodoText, addTodo } from "../actions";
      import AddTodo from "../components/AddTodo";
      
      const mapStateToProps = state => ({
        text: state.text
      });
      
      const mapDispatchToProps = dispatch => ({
        setTodoText: text => dispatch(setTodoText(text)),
        addTodo: text => dispatch(addTodo(text))
      });
      
      export default connect(
        mapStateToProps,
        mapDispatchToProps
      )(AddTodo);
      
      //FooterContainer.js
      import { connect } from "react-redux";
      import { setFilter } from "../actions";
      import Footer from "../components/Footer";
      
      const mapStateToProps = state => ({
        filter: state.filter
      });
      
      const mapDispatchToProps = dispatch => ({
        setFilter: filter => dispatch(setFilter(filter))
      });
      
      export default connect(
        mapStateToProps,
        mapDispatchToProps
      )(Footer);
      
      //TodoListContainer.js
      import { connect } from "react-redux";
      import { toggleTodo } from "../actions";
      import TodoList from "../components/TodoList";
      
      const getVisibleTodos = (todos, filter) => {
        switch (filter) {
          case "all":
            return todos;
          case "completed":
            return todos.filter(t => t.completed);
          case "active":
            return todos.filter(t => !t.completed);
          default:
            return new Error("Unknown filter: " + filter);
        }
      };
      
      const mapStateToProps = state => ({
        todos: getVisibleTodos(state.todos, state.filter)
      });
      
      const mapDispatchToProps = dispatch => ({
        toggleTodo: id => dispatch(toggleTodo(id))
      });
      
      export default connect(
        mapStateToProps,
        mapDispatchToProps
      )(TodoList);
    • 修改App.js
      import React, { Component } from "react";
      import AddTodoContainer from "../containers/AddTodoContainer";
      import TodoListContainer from "../containers/TodoListContainer";
      import FooterContainer from "../containers/FooterContainer";
      
      class App extends Component {
       
        render() {
          return (
            <div>
              <AddTodoContainer/>
              <TodoListContainer/>
              <FooterContainer/>
            </div>
          );
        }
      }
      
      export default App;  
    • 改造AddTodo.js、Footer.js、TodoList.js
      //AddTodo.js
      import React, { Component } from 'react';
      
      class AddTodo extends Component {
        
        render() {
          return (
            <div>
              <input value={this.props.text} onChange={this.handleChange}/>
              <button onClick={this.handleClick}>Add</button>
            </div>
          );
        }
      
        handleChange = (e) => {
          this.props.setTodoText(e.target.value)
        } 
      
        handleClick = () => {
          this.props.addTodo(this.props.text);
        }
      }
      
      export default AddTodo;
      
      //Footer.js
      import React, { Component } from "react";
      
      class Footer extends Component {
        render() {
          const { filter, setFilter: setVisibilityFilter } = this.props;
          return (
            <div>
              <span>Show:</span>
              <button
                disabled={filter === "all"}
                onClick={() => setVisibilityFilter("all")}
              >
                All
              </button>
              <button
                disabled={filter === "active"}
                onClick={() => setVisibilityFilter("active")}
              >
                Active
              </button>
              <button
                disabled={filter === "completed"}
                onClick={() => setVisibilityFilter("completed")}
              >
                Completed
              </button>
            </div>
          );
        }
      }
      
      export default Footer;
      
      //TodoList.js
      import React, { Component } from 'react';
      import Todo from "./Todo";
      
      class TodoList extends Component {
        render() {
          const {todos, toggleTodo} = this.props;
          return (
            <ul>
              {
                todos.map(todo => {
                  return <Todo key={todo.id} {...todo} 
                  onClick={() => {toggleTodo(todo.id)}}/>
                })
              }
            </ul>
          );
        }
      }
      
      export default TodoList;
      
      //Todo.js
      import React, { Component } from "react";
      
      class Todo extends Component {
        render() {
          const { completed, text, onClick } = this.props;
          return (
            <li
              onClick={onClick}
              style={{
                textDecoration: completed ? "line-through" : "none"
              }}
            >
              {text}
            </li>
          );
        }
      }
      
      export default Todo;  
    • index.js中: createStore、Provider、rootReducer
      import React from "react";
      import ReactDOM from "react-dom";
      import { createStore } from "redux";
      import { Provider } from "react-redux";
      import rootReducer from "./reducers";
      import App from "./components/App";
      
      const store = createStore(rootReducer);
      
      ReactDOM.render(
        <Provider store={store}>
          <App />
        </Provider>,
        document.getElementById("root")
      );

    10.回顾React组件和Redux的连接过程

    • 将组件划分为容器型组件(containers)和展示型组件(components)
    • 展示型组件:负责UI的展现,不关心数据从何而来,也不关心如何修改数据
    • 容器型组件:关注逻辑的实现,关注从何获取数据,应该如何去修改数据
    • 尽量在较低层级的组件进行连接,以减少不必要的组件渲染 (排除app.js)
    • 如果展示型组件(例如TodoList组件)不存在复用的场景,只会作为容器型组件而存在时,可以直接定义在containners目录下

    11.异步Action(调用api的Action)

    //actionTypes.js
    
    export const ADD_TODO = 'ADD_TODO'
    export const TOGGLE_TODO = 'TOGGLE_TODO'
    export const SET_TODO_TEXT = 'SET_TODO_TEXT'
    export const SET_FILTER = 'SET_FILTER'
    export const FETCH_TODOS_REQUEST = 'FETCH_TODOS_REQUEST'
    export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS'
    export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE'
    //actions->index.js
    
    import {ADD_TODO, TOGGLE_TODO, SET_TODO_TEXT, SET_FILTER, FETCH_TODOS_REQUEST, FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE} from './actionTypes'
    
    let nextTodoId = 0
    
    const fetchTodosRequest = () => ({
      type: FETCH_TODOS_REQUEST
    })
    
    const fetchTodosSuccess = (data) => ({
      type: FETCH_TODOS_SUCCESS,
      data
    })
    
    const fetchTodosFailure = (error) => ({
      type: FETCH_TODOS_FAILURE,
      error
    })
    
    /**
     * 获取待办事项初始数据
     */
    export const fetchTodos = () => {
    
      //异步action 返回的是一个函数
      return (dispatch) => {
        dispatch(fetchTodosRequest());
        return fetch("./mock/todos.json").then(
          response => {
            response.json().then(data => {
              dispatch(fetchTodosSuccess(data));
            }) 
          },
          error => {
            dispatch(fetchTodosFailure(error));
            console.log("An error occurred: "+ error)
          }
        )
      }
    }
    
    /**
     * 新增待办事项
     * @param {*} text 
     */
    export const addTodo = (text) => ({
      type: ADD_TODO,
      id: nextTodoId++,
      text
    })
    
    /**
     * 更改待办事项状态
     * @param {*} id 
     */
    export const toggleTodo = id => ({
      type: TOGGLE_TODO,
      id
    })
    
    /**
     * 设置过滤状态
     * @param {*} filter 
     */
    export const setFilter = filter => ({
      type: SET_FILTER,
      filter
    })
    
    /**
     * 设置新增待办事项的文本
     * @param {*} text 
     */
    export const setTodoText = text => ({
      type: SET_TODO_TEXT,
      text
    }) 

    12.redux-thunk中间件

    • 可以处理异步Action的中间件
    //src->index.js
    
    import { createStore, applyMiddleware } from "redux";
    import thunkMiddleware from "redux-thunk";
    
    const store = createStore(rootReducer, applyMiddleware(thunkMiddleware));
    • TodoList.js获取初始数据
    componentDidMount() {
           this.props.fetchTodos();
    }
    • TodoListContainer.js
    import { toggleTodo, fetchTodos } from "../actions";
    
    const mapStateToProps = state => ({
         todos: getVisibleTodos(state.todos.data, state.filter)
    });
    
    
    const mapDispatchToProps = dispatch => ({
         toggleTodo: id => dispatch(toggleTodo(id)),
         fetchTodos: () => dispatch(fetchTodos())
    });

    14.Redux调试工具——Redux DevTools

    • 支持Crome浏览器和Firefox浏览器
    //src->index.js
    import { createStore, applyMiddleware, compose } from "redux";
    
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunkMiddleware)));
    

    注:项目来自慕课网  

    人与人的差距是:每天24小时除了工作和睡觉的8小时,剩下的8小时,你以为别人都和你一样发呆或者刷视频
  • 相关阅读:
    c++ 与 c 的区别
    c++ 查看程序运行时间
    串口阻塞与非阻塞
    串口缓冲区
    马拉车算法
    printf 自加自减
    stack
    长度问题
    PCIE的内存地址空间、I/O地址空间和配置地址空间
    数组和指针
  • 原文地址:https://www.cnblogs.com/ljq66/p/14376041.html
Copyright © 2020-2023  润新知