React入门:组件化思想?数据驱动?

React是个啥?

React 是一个用于构建用户界面的 JavaScript 库 ,由 Facebook于2011年开发并开源。它的核心目标是高效、灵活地构建动态网页应用

简单来说,React 让你用 组件(Component) 的方式搭建界面,就像用乐高积木拼装玩具一样:

  • 每个组件负责一块功能(如按钮、导航栏、数据列表)。
  • 组件可以组合、复用,不同拼凑好的积木重新组合成新东西。
  • 数据变化时,React 自动更新界面,无需手动操作 DOM。

为什么选择React?

React和传统的DOM(Document Object Model)编程相比,让我们不再需要把精力聚焦在细节上,比如同一段需求实现,DOM编程和React相比:

js 复制代码
// 手动找到DOM元素并修改
const element = document.getElementById('armor-status');
element.innerHTML = '能量剩余: 75%';
element.style.color = 'orange';
js 复制代码
// 直接描述"UI应该是什么样子"
function ArmorStatus() {
  return (
    <div style = {{ color: 'orange' }} >
      能量剩余: {75}%
    </div>
  );
}

其次,我们将某一些功能封装 成了一个组件,这个组件又可以在其他地方使用,大大提升了复用性,就拿B站的来举例吧:

这是B站主页的部分组件,最常用的应该就是导航栏组件了,这个组件的复用性极高,如果我们利用传统的JS,那只能对这个组件的代码CV了,但是如果利用React,我们就可以将其封装成一个组件(Component),在需要的时候直接将组件嵌入即可。

下面是b站其他网页应用导航栏的例子:

如何创建React?

既然大家对于React有了一个基础的认知了,那么下面我们就一起来创建一个React项目吧。

首先创建一个文件夹,在里面存放react项目,文件名自定义,之后在终端中输入以下命令:

cmd 复制代码
npm init vite

之后取个文件名

按小键盘上下来选择框架类型,选择React,再选择JavaScript

接下来根据提示逐一执行命令: 所有命令执行完毕后,打开其提供的链接:

这样你的第一个React项目就创建完毕了。

如何理解组件化/数据驱动?

接下来让我们以一个例子来走进React的这两个特性,我们来做一个TodoList:

做一个输入框,一个button,将要做的事情输入并展现在输入框下面。

首先我们先删除App.jsx到这样:

之后在src文件下创建 components 文件夹,在里面创建 TodoList.jsx文件

组件化

我们的功能模块都是封装成一个个组件的,而App.jsx就是我们的根组件,也就是说其他的组件要挂载到这上面,在App.jsx的基础上进行展示,那么我们就可以将TodoList.jsx挂载到App中:

jsx 复制代码
import TodoList from './components/TodoList' // 引入TodoList
import './App.css'

function App() {
 

  return (
   <>
   <TodoList/> <!--作为组件之一,挂载到模板上-->
   
   </>
      
  )
}

export default App

接下来我们可以编写Todolist的内容了:

jsx 复制代码
function TodoList(){
    const title = "Todo List";
    const hi = "Hello World";
           return (
            
        <div className="container" style={{color:"red"}}>
            <h1>{title}</h1>
            <h2>{hi}</h2>
        </div>
    )

}
export default TodoList; // 记得将函数导出,只有货物出口了,所需的国家(App.jsx)才能进口

什么是组件

就上面的例子来看,组件就是html+css+js的一个结合,是一个开发单元,一个功能的实现就可以放到一个组件中,它的本质就是返回了一个函数,函数里面的返回值返回了相应的元素,同时实现了某些功能。

比较来讲,之前的DOM编程,html和css以及JS都是分开来写的,现在有了react,我们把它们组合来写,不再分开去写,而是将要实现功能的html、css、JS全部组合到一起,实现了组件化开发

如何划分组件?

TodoList 为例,函数就是一个组件,return之前可以写JavaScript的各种数据和逻辑,return直接返回html,以类字符串模板的形式,将数据嵌入到html标签内,可以更加方便的实现数据传递动态更新的功能。

组件化思想:现代前端开发的基石

在前端开发领域,组件化思想 已经成为所有现代框架(React、Vue、Svelte等)的核心设计理念。它彻底改变了我们构建用户界面的方式,将开发模式从传统的DOM树编程 升级为更高效的组件树编程

1. 从"沙子"到"砖块"的进化

如果把构建网页比作建造一面墙:

  • 传统HTML就像是散落的沙子------虽然能完成基础结构,但缺乏工程化的组织方式
  • 组件则是预制的砖块------每个组件都封装了相关的HTML结构、CSS样式和JavaScript逻辑,成为一个完整的功能单元

例如,一个<TodoItem>组件就包含了任务展示、完成状态切换和删除等完整功能,开发者无需关心内部DOM操作细节。

2. 组件的核心优势
  • 功能封装 :将相关的UI和逻辑组合成独立单元(如<SearchBar><ProductCard>
  • 极致复用 :像乐高积木一样重复使用(一个<Button>组件可在全项目通用)
  • 协作开发:不同开发者可以并行开发不同组件
3. 组件化开发范式

现代前端项目本质上就是组件树的组合

graph TB A[App] --> B[Header] A --> C[ProductList] C --> D[ProductCard] C --> E[Pagination]

通过这种层级结构,复杂页面被分解为可维护的独立单元。开发者只需关注:

  1. 如何合理拆分组件(原子设计原则)
  2. 组件间的数据流动(props/state管理)
  3. 业务逻辑的实现(而非DOM操作)

这种模式让前端开发真正聚焦于业务价值而非底层实现,这也是React等框架迅速崛起的关键原因。


表单输入

接下来让我们编写另一个组件TodoForm.jsx用来添加输入框和提交按钮,首先在components文件夹下创建TodoForm.jsx:

jsx 复制代码
import { useState } from "react";


function TodoForm(props) {
    return (
        <form className="form" >
            <input type="text" className="input" placeholder="Add a todo..." />
            <button type='submit' className="button">Add</button>
             
        </form>
        
    )
}
export default TodoForm;

再利用import TodoForm from'./TodoForm'将其添加至Todolist.jsx即可

jsx 复制代码
import TodoForm from'./TodoForm'
import Todos from'./Todos'
function TodoList(){
    const title = "Todo List";
    const hi = "Hello World";
           return (
            
        <div className="container">
            <h1>{title}</h1>
            <h2>{hi}</h2>
            <TodoForm/>
            <Todos/> <!--将下面展示列表的功能模块暂时命名为Todos;-->
        </div>
    )

}
export default TodoList;

这样第二个模块就写好了,接下来就是要处理数据传输的逻辑了:

当我们利用表单提交数据,我们希望其不要刷新页面,并将表单数据提交到当前页面,所以就对其修改如下:

jsx 复制代码
import Todos from "./Todos";
import { useState } from "react";


function TodoForm() {
    
    
    const [text, setText] = useState('打豆豆') // 状态的初始值
    const handleChange = (e) => { // 事件处理函数  事件对象e  event object
        setText(e.target.value)
    
    }
        const handleSubmit = (e) => {
        console.log(e);
        e.preventDefault(); // event api
        
        
    }
    
    return (
        <form className="form" onSubmit={handleSubmit} action="localhost:5173">
            <input type="text" className="input" placeholder="Add a todo..." value={text} onChange={handleChange}/>
            <button type='submit' className="button">Add</button>
             
        </form>
        
    )
}
export default TodoForm;

value给表单内容设置了个初始值为text,为什么要用onchange呢?因为当你设置这个初始值后,这个初始值是常量,不可改变,所以就需要利用onchange时刻检测text的变化,并利用setText展示出来并修改原Text的值。

数据驱动

有的同学会疑问,const[text,setText] = useState('打豆豆')是个什么鬼?

这就是React的精髓了,useState顾名思义就是使用状态,React将纯数据转换成了数据状态 ,这一个语句是一个解构赋值,当你用输出展示useState中都有什么东西时,你会发现useState[0]是它的初始值,我们在这里将其设置为了打豆豆,useState[1]是一个函数,用于改变Text的值。

什么叫数据驱动?简而言之,就是数据在更新时,页面内容才会发生更改,自动更新,在这里就是数据状态的改变,数据状态的改变驱动着页面的变化,比如写一个时钟,随着时间不断更改,React每检测到数据变化就会将相应的变化利用虚拟DOM驱动真实DOM发生更改呈现在页面上。

为什么是虚拟DOM?它有什么用?

在框架设计的时候,由于React是数据驱动的,一个组件中可能有100个数据,某一个数据发生了变化,我就要去更新它,但它由于很多问题,导致它检测不出来哪个发生了变化,所以它就有个render函数,我用render将数据全部重新加载,全量生成页面,那么利用真实DOM开销就很昂贵了,所以就开发了虚拟DOM,其利用数据改变后创建的虚拟DOM与之前的真实DOM利用diff比较,找到不一样的再操作真实DOM发生改变,其在某种程度上是增进了一定的效率。

OK,继续,我们由于需要进行数据的接收和更新,所以我们需要对TodoList.jsx进行改进:

jsx 复制代码
const [todos, setTodos] = useState([
        {
            id: 1,
            title: 'todo 1',
            completed: false,
        }        // 初始化一个todo列表
    ]) 
    
// useState是一个hook函数,
// 返回一个数组,
// 第一个元素是状态,

const handleAdd = (text) =>{
    setTodos([
        ...todos,  //展开原来数组
        {
            id:todos.length+1,
            title:text,
            completed:false,
        }

    ])
}


return (
<TodoForm onAdd={handleAdd}/>  //对这俩元素进行改变,将函数和数据分别传递给子组件
<Todos todos={todos}/>
// 将 handleAdd函数传过去,传过去的函数名叫onAdd
// 将 todos 数组传递过去,传过去的数组名叫todos
)

之后子组件更新逻辑,调用父组件的函数来实现todos的更新(TodoForm.jsx完整版):

jsx 复制代码
import Todos from "./Todos";
import { useState } from "react";


function TodoForm(props) {
    
    const onAdd = props.onAdd;
    const [text, setText] = useState('打豆豆') // 状态的初始值
    const handleChange = (e) => { // 事件处理函数  事件对象e  event object
        setText(e.target.value)
    
    }
        const handleSubmit = (e) => {
        console.log(e);
        e.preventDefault(); // event api
        // 如何修改todos?  由于是父组件的,改不了,所以只能打报告
        onAdd(text)
        
    }
    
    return (
        <form className="form" onSubmit={handleSubmit} action="localhost:5173">
            <input type="text" className="input" placeholder="Add a todo..." value={text} onChange={handleChange}/>
            <button type='submit' className="button">Add</button>
             
        </form>
        
    )
}
export default TodoForm;
jsx 复制代码
// 列表的渲染

import TodoForm from "./TodoForm";

function Todos(props) {
  // 利用参数拿到父组件传来的数据状态
  const todos = props.todos;
  console.log(props + '/////');
  
  return( 
    <ul>
    {   //数据绑定 data binding
      // 数据驱动
      // 发生改变后 自动地改变界面
      todos.map(todo=>(
          <li key={todo.id}>{todo.title}</li>
      ))   // 利用map循环更新
  }

  </ul>
  
  )
}

export default Todos;

TodoList:

jsx 复制代码
import { useState } from 'react' // 内置的hook函数
import '../Todo.css'
import TodoForm from './TodoForm'
import Todos from './Todos'
function TodoList() {
    const[hi,setHi] = useState('haha');
    const [title,setTitle] = useState('Todo_list') 
    // 数据 -》 变化 -》 数据状态 -> 自动刷新页面 -》数据驱动(drive)页面
    // 数据 ↓
    const [todos, setTodos] = useState([
        {
            id: 1,
            title: 'todo 1',
            completed: false,
        }
    ]) 

const handleAdd = (text) =>{
    setTodos([
        ...todos,
        {
            id:todos.length+1,
            title:text,
            completed:false,
        }

    ])
}

    return (
        <div className="container">
            <h1>{title}</h1>
            <h2>{hi}</h2>
            <TodoForm onAdd={handleAdd}/>
            <Todos todos={todos}/>
        </div>
    )
}


export default TodoList

总结

通过这个例子,我们要学会组件化思想,看到需求先想想能划分成几个组件,将各自的逻辑封装在里面,最后集中挂载到一个根组件去展示,要理解 data-binding 数据绑定和数据驱动的意义,在这个例子中, 由于form表单每次更新都会触发onAdd函数,每一次都会对todos进行更新,最后使得页面进行更新,这就是数据驱动。

相关推荐
小桥风满袖1 分钟前
Three.js-硬要自学系列30之专项学习环境光
前端·css·three.js
Luckyfif4 分钟前
🤯由 性能指标 散发开来的 Performance API 被问爆了呀
前端·面试·性能优化
咸虾米7 分钟前
在uniCloud云对象内使用unipay的微信退款出现错误“uniPayCo.refund Error: token校验未通过”的解决方案
前端·后端
前端Hardy13 分钟前
HTML&CSS:产品卡片动画效果
前端·javascript
货拉拉技术19 分钟前
货拉拉开源:鸿蒙路由 TheRouter
android·前端·harmonyos
中杯可乐多加冰21 分钟前
工业4.0数字孪生新引擎:星图云开发者平台全景评测
前端·低代码·掘金·金石计划
云边小卖铺.28 分钟前
运行vue项目报错 errors and 0 warnings potentially fixable with the `--fix` option.
前端·javascript·vue.js
我是若尘29 分钟前
前端处理大量并发请求的实用技巧
前端
Lstmxx31 分钟前
Electron:使用数据流的形式加载本地视频
前端·electron·node.js