赞
踩
React是一个由Facebook开发并开源的JS框架,用于构建用户界面。它主要用来创建可复用组件、处理用户交互和管理数据。它的特点包括快速渲染、声明式编程、组件化开发和React Native支持。它的架构由两大部分组成:
Action 是 Redux 中的基本组成单位,它描述应用程序所需执行的动作,并且可以携带一定的数据。在 Redux 中,每个 action 都是 JavaScript 对象,必需有 type 属性。一般情况下,action creator 会生成一个 action 对象。比如,如果需要创建一个 action,用来改变 counter 的值,可以定义如下:
const changeCounter = value => {
return {
type: 'CHANGE_COUNTER',
payload: value
};
};
Reducer 函数是 Redux 中最重要的部分之一,它是个纯函数,接收先前的 state 和 action,返回新的 state。Reducer 函数根据 action 的类型决定如何更新 state 。比如,下面是改变 counter 的 reducer 函数:
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return {...state, count: state.count + 1 };
case 'DECREMENT':
return {...state, count: state.count - 1 };
default:
return state;
}
}
Dispatch 是 Redux API 中最常用的方法之一,它可以触发 action 的生成和传递,例如:
import { increment, decrement } from './actions';
dispatch(increment()); // dispatch the INCREMENT action
dispatch(decrement()); // dispatch the DECREMENT action
Middleware 可以理解为拦截 Redux 的 action 执行过程,比如日志记录、异步请求、异常处理等。中间件通常是实现 Redux 插件功能的一种方式。官方提供的三个中间件分别是 thunk、promise middleware 和 logger。Thunk 是一个中间件,用来实现 Redux 中间件的异步操作。Promise middleware 是另一个中间件,用来处理异步 Promise 请求。Logger 是第三种中间件,用来打印 Redux 的日志。
React组件是视图层的核心构建模块,它负责完成渲染和逻辑交互。每个 React 应用都由不同类型的组件组合而成,这些组件之间又存在依赖关系。组件的 Props 和 State 用来维护组件的局部和全局状态。Props 是父组件向子组件传递数据的方法,State 则用来在组件内记录数据的变化。
State 和 Props 是 React 中两个最基本的概念,它们是用来管理组件状态和配置信息的。State 代表的是当前组件内部数据的状态,它应该是私有的,只能在组件自身使用,外部无法直接访问或修改。Props 是父组件传递给子组件的数据,它是父组件对子组件的约束条件,外部也可以访问并修改。除此之外,还有其他几个关于状态的概念,如局部状态(Local State)、共享状态(Shared State)等。
项目结构按照 Redux 规范一般分为以下几部分: 1.Actions 文件夹:存放所有的 action 创建函数文件。 2.Reducers 文件夹:存放所有的 reducer 函数文件。 3.Store 文件夹:存放 Redux 配置文件。 4.Components 文件夹:存放 UI 组件。 5.Containers 文件夹:用于连接 Redux 数据和 UI 组件的文件。 6.Routes 文件夹:用于定义路由规则。
npm install redux react-redux --save
在 Actions 文件夹下创建 actions.js
文件,用于定义 action 创建函数。
export const addTodo = text => ({ type: 'ADD_TODO', text }); export const toggleTodo = index => ({ type: 'TOGGLE_TODO', index }); // 添加 todos 初始化函数 export function loadTodos() { return async dispatch => { try { const response = await fetch('https://jsonplaceholder.typicode.com/todos'); const data = await response.json(); console.log(data); dispatch({ type: 'LOAD_TODOS', data: data }); } catch (error) { console.error(error); } }; }
在 Reducers 文件夹下创建 reducers.js
文件,用于定义 reducer 函数。
const initialState = { todos: [], visibilityFilter: 'SHOW_ALL' }; const todoApp = (state = initialState, action) => { switch (action.type) { case 'ADD_TODO': return { todos: [...state.todos, { text: action.text, completed: false }], visibilityFilter: state.visibilityFilter }; case 'TOGGLE_TODO': let newTodos = [...state.todos]; newTodos[action.index].completed =!newTodos[action.index].completed; return { todos: newTodos, visibilityFilter: state.visibilityFilter }; case 'SET_VISIBILITY_FILTER': return { todos: state.todos, visibilityFilter: action.filter }; case 'LOAD_TODOS': return { todos: action.data, visibilityFilter: state.visibilityFilter }; default: return state; } }; export default todoApp;
在 Store 文件夹下创建 store.js
文件,用于定义 Redux 配置。
import { createStore } from'redux';
import rootReducer from '../reducers/rootReducer';
const store = createStore(rootReducer);
export default store;
创建 Containers 文件夹,用于存放连接 Redux 数据和 UI 组件的文件。
在 Containers 文件夹下创建 TodosListContainer.js
文件,用于连接 Redux 数据和 UI 组件。
import { connect } from'react-redux'; import { setVisibilityFilter, toggleTodo, addTodo } from '../actions'; import TodoList from '../../components/TodoList'; const mapStateToProps = state => { return { todos: state.todoApp.todos, visibilityFilter: state.todoApp.visibilityFilter }; }; const mapDispatchToProps = dispatch => { return { onSetFilter: filter => dispatch(setVisibilityFilter(filter)), onToggleTodo: index => dispatch(toggleTodo(index)), onAddTodo: text => dispatch(addTodo(text)) }; }; const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList); export default VisibleTodoList;
创建 Components 文件夹,用于存放 UI 组件。
在 Components 文件夹下创建 TodoTextInput.js
文件,用于输入添加 ToDo 任务。
import React from'react'; class TodoTextInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleChange = e => { this.setState({ text: e.target.value }); }; handleSubmit = e => { e.preventDefault(); if (!this.state.text.trim()) { return; } this.props.onAddTodo(this.state.text); this.setState({ text: '' }); }; render() { return ( <div> <form onSubmit={this.handleSubmit}> <input placeholder="What needs to be done?" autoFocus value={this.state.text} onChange={this.handleChange} /> <button>{'Add #' + (this.props.todos.length + 1)}</button> </form> </div> ); } } export default TodoTextInput;
在 Components 文件夹下创建 VisibilityFilters.js
文件,用于选择展示哪些任务。
import React from'react'; import PropTypes from 'prop-types'; const filters = { SHOW_ALL: 'Show All', SHOW_COMPLETED: 'Show Completed', SHOW_ACTIVE: 'Show Active' }; class VisibilityFilters extends React.Component { static propTypes = { currentFilter: PropTypes.string.isRequired, onFilterChange: PropTypes.func.isRequired }; handleClick = filter => { this.props.onFilterChange(filter); }; render() { return ( <ul className="filters"> {Object.keys(filters).map(filterKey => ( <li key={filterKey}> <a href="#" onClick={() => this.handleClick(filterKey)} className={ filterKey === this.props.currentFilter ?'selected' : '' } > {filters[filterKey]} </a> </li> ))} </ul> ); } } export default VisibilityFilters;
在 Components 文件夹下创建 Footer.js
文件,用于显示脚部信息。
import React from'react'; class Footer extends React.Component { shouldComponentUpdate() { return false; } render() { const activeCount = this.props.todos.filter(todo =>!todo.completed).length; const itemWord = activeCount!== 1? 'items' : 'item'; return ( <p> Showing {activeCount} of {this.props.todos.length}{' '} {itemWord} left </p> ); } } export default Footer;
在 Components 文件夹下创建 App.js
文件,用于显示整个应用。
import React, { useState } from'react'; import { BrowserRouter as Router, Switch, Route } from'react-router-dom'; import { addTodo } from '../actions'; import AddTodo from './AddTodo'; import VisibleTodoList from './VisibleTodoList'; import Footer from './Footer'; const inititalTodos = [ { id: 0, text: 'Use Redux', completed: true }, { id: 1, text: 'Run a marathon', completed: false }, { id: 2, text: 'Write a book', completed: false }, { id: 3, text: 'Buy a TV', completed: true } ]; function App() { const [todos, setTodos] = useState(inititalTodos); const [visibilityFilter, setVisibilityFilter] = useState('SHOW_ALL'); const handleAddTodo = text => { const newTodos = [ ...todos, { id: Math.random(), text, completed: false } ]; setTodos(newTodos); }; const filteredTodos = () => { switch (visibilityFilter) { case 'SHOW_COMPLETED': return todos.filter(todo => todo.completed); case 'SHOW_ACTIVE': return todos.filter(todo =>!todo.completed); default: return todos; } }; return ( <Router> <div> <h1>My Todos</h1> <Switch> <Route path="/" exact component={AddTodo} /> <Route path="/list" component={VisibleTodoList} /> </Switch> <Footer todos={filteredTodos()} visibilityFilter={visibilityFilter} onFilterChange={setVisibilityFilter} /> </div> </Router> ); } export default App;
在根目录下修改 index.js
文件,用于导出 store 对象。
import React from'react'; import ReactDOM from'react-dom'; import './styles/global.css'; import App from './containers/App'; import registerServiceWorker from './registerServiceWorker'; import { createStore } from'redux'; import { Provider } from'react-redux'; import rootReducer from './reducers'; const store = createStore(rootReducer); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); registerServiceWorker();
npm install prop-types react-router-dom --save
以上安装完毕后,项目的依赖包如下图所示:
运行项目,打开浏览器,输入 http://localhost:3000/
,即可看到页面效果如下图所示:
我们可以查看初始时页面加载时默认展示的 ToDos 是否正确。
我们可以在输入框输入文字后点击按钮添加 ToDo 任务。
我们可以点击圆圈勾选标记的任务后,再点击顶部删除按钮删除已完成任务。
我们可以选择展示全部、待办或已办的任务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。