React + Redux + Webpack 项目实战

· 约 26 分钟读完

在前端开发中,React、Redux 和 Webpack 是目前最流行的技术栈之一。React 作为视图层的框架,可以帮助开发者快速构建复杂的用户界面。Redux 则用来管理应用的状态,并提供可预测性和一致性。Webpack 是打包工具,可以将各种资源打包成最终的应用程序。在本文中,我们将深入探讨如何使用这三种技术,以 React + Redux + Webpack 为例,开发一个简单的 Todo 应用,并介绍一些关键性的概念和技巧。

项目结构

首先,我们需要创建一个项目。在本文中,我们采用一个简单的目录结构,它包括:

在上述目录结构中,src 目录是我们的源代码,它包含组件、容器、reducer 和 action 等文件。webpack.config.js 是 Webpack 的配置文件,package.json 则是项目的依赖配置文件。

编写组件

在 React 中,一个组件就是一个 JavaScript 函数或类,它负责渲染特定的 UI 部分。我们的 Todo 应用包含以下四个组件:

  1. AddTodo 组件:用于添加新的 Todo 到列表中。
  2. TodoList 组件:显示列表中的所有 Todo。
  3. Todo 组件:显示单个 Todo 的详细信息。
  4. Filter 组件:用于切换显示的 Todo 列表。

下面我们将逐一介绍这些组件的实现。

AddTodo.js

AddTodo 组件渲染一个 input 元素和一个 button 元素,让用户添加新的 Todo。

在上面的代码中,我们使用一个 ref 属性来获取 input 元素的引用,并将其赋值给 input 变量。当用户点击“Add Todo”按钮时,会调用 onAddClick 回调,该回调将会传入输入框中的文本。之后,我们将文本框的值清空。这样,用户就可以一遍又一遍地添加 Todo 了。

Todo.js

Todo 组件渲染一个单独的 Todo 项,包括它的文本内容和一个删除按钮。

在上面的代码中,我们使用了一个 JavaScript 对象作为样式,并将其传递给 span 元素。当用户点击 Todo 时,会调用 onClick 回调,该回调将会标记当前 Todo 项为已完成或未完成。当用户点击删除按钮时,会调用 onDeleteClick 回调,该回调将会从列表中删除当前 Todo。

TodoList.js

TodoList 组件渲染整个 Todo 列表。它从 todos 属性中获取一个包含所有 Todo 的数组,并使用 map 函数将其转换成一个个 Todo 组件。

在上面的代码中,我们使用展开运算符 ...,将 todo 对象的所有属性传递给 Todo 组件,而不是一个一个地传过去。这样做可以减少代码量,并保持代码的简洁性。在 map 函数中,我们还使用了 key 属性,它用于标识每个 Todo 组件,以便 React 可以对其进行高效更新。

Filter.js

Filter 组件渲染三个链接,用于切换 Todo 列表的显示方式。当用户点击某个链接时,会调用 onClick 回调,该回调将会改变当前的过滤条件。

在上面的代码中,我们使用 href 属性和 preventDefault 函数来防止调用默认的链接点击行为。当链接被点击时,我们将调用 onFilterChange 回调函数来更新过滤条件。如果当前链接对应的过滤条件与当前选中的过滤条件匹配,则我们使用 underline 样式来标识链接。

编写容器

在 React 和 Redux 中,容器组件是将组件连接到 Redux store 的组件。容器组件被用于将 Redux 和 React 组件集成在一起。我们的 Todo 应用中包含一个名为 VisibleTodoList 的容器组件,它用于将 TodoList 组件连接到 Redux store。

VisibleTodoList.js

VisibleTodoList 容器组件从 Redux store 中获取 todos 和 visibilityFilter 两个状态。在 componentDidMount 生命周期函数中,它将注册一个 Redux store 的监听器,并在组件卸载时取消注册该监听器。当状态发生改变时,VisibleTodoList 会重新渲染 TodoList 组件,并将过滤条件和需要显示的 Todo 传递给它。

在上面的代码中,我们使用了 connect 函数将 TodoList 组件连接到 Redux store。mapStateToProps 函数将 store 中的状态映射到组件的 props 属性,mapDispatchToProps 函数映射 dispatch 函数。

编写 Reducer 和 Action

在 Redux 中,我们使用 action 来描述发生了什么,使用 reducer 来更新应用的状态。在我们的 Todo 应用中,有两种类型的 action:ADD_TODO 和 TOGGLE_TODO;同时,有一个过滤条件的 action:SET_VISIBILITY_FILTER。

actions/todos.js

ADD_TODO action 表示添加一个新的 Todo。因此,它需要一个唯一的 id 和一个 Todo 的 text。

TOGGLE_TODO action 表示切换 Todo 的状态(completed 或未 completed)。因此,它需要一个 Todo 的 id。

DELETE_TODO action 表示删除一个 Todo。因此,它需要一个 Todo 的 id。

actions/visibilityFilter.js

SET_VISIBILITY_FILTER action 表示设置显示的过滤条件。因此,它需要一个过滤条件值(SHOW_ALL、SHOW_ACTIVE 或 SHOW_COMPLETED)。

reducers/todos.js

todos reducer 用于接收 ADD_TODO、TOGGLE_TODO 和 DELETE_TODO 三种 action,并返回新的 todos 状态。在 ADD_TODO action 中,我们创建一个新的 Todo 对象,将其添加到列表中。在 TOGGLE_TODO action 中,我们遍历列表,找到要切换的 Todo,并将其 completed 属性切换为相反的值。在 DELETE_TODO action 中,我们遍历列表,找到要删除的 Todo,并将其从列表中删除。

reducers/visibilityFilter.js

visibilityFilter reducer 用于接收 SET_VISIBILITY_FILTER action,并更新过滤条件。

编写入口文件

最后,我们需要编写一个入口文件,将我们的组件和容器组件集成在一起,并渲染到页面中。

index.js

在上面的代码中,我们使用 createStore 函数创建一个 Redux store,并将 rootReducer 传递给它。然后,我们将 store 传递给 Provider 组件,并将 App 组件渲染到页面中(这里 App 组件包含了所有的组件和容器组件)。

编写 Webpack 配置

最后,我们需要定义一个 Webpack 配置文件,用于将 src 目录下的代码打包成一个 bundle.js 文件,并将其引入到 index.html 文件中。

webpack.config.js

在上面的代码中,我们定义了入口文件,输出文件,模块定义和 devServer 选项。其中,我们使用了 babel-loader 和 @babel/preset-env 和 @babel/preset-react 两个 Babel 插件,来将我们的 ES6 和 JSX 代码转换成普通的 JavaScript。我们还使用了 style-loader 和 css-loader 两个插件来处理 CSS 文件。最后,我们定义了 devServer 选项,用于运行一个开发服务器,方便我们开发和测试。

整合所有代码

在上述的代码编写完成后,我们可以将它们整合起来,来创建我们的 Todo 应用。

src/index.js

src/components/App.js

src/components/AddTodo.js

src/components/Filter.js

src/components/Todo.js

src/components/TodoList.js

src/containers/VisibleTodoList.js

src/reducers/index.js

src/reducers/todos.js

src/reducers/visibilityFilter.js

src/index.html

src/main.css

结语

在本文中,我们介绍了如何使用 React、Redux 和 Webpack 来开发一个完整的 Todo 应用程序。通过这个实例,我们深入学习了组件、容器、reducer 和 action 等关键性概念和技巧。同时,我们还学习了如何通过 Webpack 来打包和部署我们的应用程序。希望通过这篇文章的学习,读者们能够更加深入地掌握 React、Redux 和 Webpack 的使用方法,并能够使用它们来开发更为复杂的应用程序。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7fd2fa941bf7134e43481