React快速入门(核心概念+实战篇)

React快速入门

全部代码:https://github.com/ziyifast/front-demo

  • React特点:
  1. 声明式设计:声明范式
  2. 高效:使用VDOM,减少DOM的交互
  3. 灵活:与已知的库或框架完好配合
  4. JSX:一种独立的语言,试图解决很多JS的缺陷,ES6包含了几乎所有JSX的特性
  5. 组件:代码复用
  6. 单向响应数据流:比双向绑定更简单,更快。

1 核心篇

准备:创建项目

我这里使用VSCode创建项目,在终端执行下面命令

# 通过脚手架创建项目
npx create-react-app 1-react-core-demo
# npx create-react-app@latest # 创建项目,自选功能# 进入项目
cd 1-react-core-demo# 启动项目
npm start

App.js为React默认主页面

在这里插入图片描述

1.1 核心概念及语法

①组件:函数式组件

React分为函数式组件和类组件,官方推荐使用函数式组件,因为类组件编写起来较复杂。我这里主要演示类组件用法。

App.js:

解释:我下面定义了一个函数式组件App,并且将其return暴露

  • 注意点:
  • React使用语法为JSX(JS+HTML),只能有一个根标签=》<></>或者Fragment。所以我在多个<div>标签外用<>标签包裹了一层
import './App.css';function App() {return (// JSX(JavaScript+HTML)规定只能有一个根标签,如果需要添加标签// 1. 可以在外面嵌套一层<div>// 2. 使用<></>空标签// 3. 如果有id,可以使用Fragment<><div className="App"><div>let's do it</div></div><div>who want to try ?</div></>);
}export default App;
②插值

解释:类似引用,我先定义一个值,然后通过{变量名}引用值

App.js

function App() {// 插值(先定义变量,然后通过花括号引用值):{} let content = "hello world"return (<div>{content}</div>);
}export default App;
③数据渲染

数据渲染主要有:

  1. 条件渲染(if)
  2. 列表渲染(array)=> map遍历
import './App.css';function App() {// 数据渲染:// 1. 条件渲染// 2. 列表渲染//--------------1. 条件渲染-------------// let content = "hello world"// let flag = false// if (flag) {//   //注意:此处不用加引号//   content = <div>老侄,flag为true</div>// } else {//   content = <div>大舅,flag为false</div>// }// return (//     <div className="App">//       <span>嘿 man</span>//       {content}//     </div>// );//--------------2. 列表渲染-------------let userList = [{id:1,name:"徐杰"},{id:2,name:"郭艾伦"},{id:3,name:"易建联"}]// 通过map来遍历const listContent = userList.map((item,index)=>{return <li key={index}>{item.name}</li>})return (<div className="App"><div>{listContent}</div></div>);
}
export default App;
④事件处理
  1. 定义function
  2. 通过{funciton_name}引用
  3. 标签内绑定事件,onClick等
import './App.css';function App() {// 事件处理:无法实现响应式效果,需要结合useState来实现function handleClick(e){console.log("浏览器传入的值:"+e.target.innerText);}return (<div className="App"><button onClick={handleClick}>Click me</button></div>);
}
export default App;
⑤状态:useState

通过useState实现响应式效果

  • const [content, setContent] = useState(“Hello World”)
  • useState会返回一个数组,第一个值为保存的值,第二个值是一个func,用于设置新的值
import './App.css';
import {useState} from 'react'; //导入钩子函数function App() {// 状态处理:useState实现,本质是将之前的值全部替换,因此setContent需要带上之前的值// 1. 字符串// 2. 对象// 3. 数组//------------------1. 字符串--------------------// const [content, setContent] = useState("Hello World")// function handleClick(){//   setContent("中国🇨🇳男篮")// }// return (//   <div className="App">//     <div>{content}</div>//     <button onClick={handleClick}>Click me</button>//   </div>// );//------------------2. 对象--------------------// const [content, setContent] = useState({//   name:"Jackson",//   age:20// })// function handleClick(){//   setContent({//     ...content, //...content是将对象之前的内容全部拿过来(useState的set操作是全部替换,如果这里只赋值age,那么会丢失name)//     age:18 //如果之前了age字段,那么我们这里再赋值就会替换之前的值//   })// }// return (//   <div>//     <div>{content.name}</div>//     <div>{content.age}</div>//     <button onClick={handleClick}>点我变小</button>//   </div>// )//------------------3. 数组--------------------const [content, setContent] = useState([{id:1, name:"库里"},{id:2, name:"欧文"},{id:3, name:"姚明"},])const listData = content.map(item => (<li key={item.id}>{item.id}-{item.name}</li>))//点击之后在默认添加元素function handleClick(){setContent([...content,{id:4, name:"詹姆斯"}])}//点击之后通过filter删除元素function handleClick2(){setContent(content.filter(item => item.id !== 2))}return (<div><ul>{listData}</ul><div>what?</div><button onClick={handleClick}>点我新增</button><button onClick={handleClick2}>点我删除2</button></div>)
}
export default App;

1.2 组件通信与插槽

组件:

  • React DOM组件
  • React 自定义组件
①React DOM组件:如img标签
import './App.css';
import image from './logo.svg'function App(){// 操作React DOM组件(原生html的一些标签)const imgData = {className: 'small',style: {width: '100px',height: '100px'}}return (<div><img src = {image}alt = "悬浮文字xxx"{...imgData}/>  </div>)
}export default App;
②自定义组件:function xxx

前面我们介绍了react主要有函数式组件与类组件,下面我将演示如何自定义函数式组件

// 自定义组件
// 父组件向子组件传值:通过props,如:{text,active}
function Detail({text,active}){return (<><p>{text}</p><p>状态:{active ? '显示中' : '已经隐藏'}</p></>)
}function Article({title, content}) {return (<div><div>{title}</div><Detail {...content}/></div>)
}export default function App(){const articleData = {title: '文章标题',content:{'text': '文章内容','active': true}}return (<><Article{...articleData}/></>)
}
③实现插槽效果:children
  • JSX实现Vue插槽效果=》 children(简单版props,children被预先定义)
  • 运行下面的代码可以知道我把<li>等标签及内容页传给了List组件,实现了类似Vue插槽效果

App.js

// JSX:实现类似Vue插槽效果:通过children传递(children这个属性是固定的)
function List({children}){return (<ul>{children}</ul>)
}export default function App(){return (<><List><span>第一列</span><li>列表项1</li><li>列表项2</li><li>列表项3</li></List><List><span>第二列</span><li>列表项a</li><li>列表项b</li><li>列表项c</li></List></>)
}
④子组件向父组件传值
  • 子组件向父组件传值=》自定义事件=》子组件触发事件来对应修改父组件(如果组件的值是可选的,那么需要在参数那赋值一个默认值,否则会有语法错误)
  • 同级组件传值=》常用做法:通过父组件做一个中转
  • 多级组件传值=》context=>createContext、useContext,通过Provider设置值

import {useState} from 'react' //注意手动:引入时,不要忘记{}// 子组件向父组件传值=》自定义事件=》子组件触发事件来对应修改父组件
function Detail(){const [status, setStatus] = useState(false)function changeStatus(){setStatus(!status)}return (<div><button onClick={changeStatus}>点我有惊喜</button><p style={{display:status?'block':'none'}}>大聪明~</p></div>)
}export default function App(){return (<div><Detail /></div>)
} 

1.3 React Hooks

下面我将介绍React常用的几个钩子函数

  • react 函数组件的钩子函数(hook) hook函数是一个特殊的函数,目的是让函数组件也有类组件的特性. 类组件中可能一个周期函数中有多个业务逻辑代码,不利于维护. 类组件的学习成本相对较高,需要掌握es6的语法.
①useState:定义和更新组件的局部状态。
import {useState} from 'react'
export default function App(){const [score, setScore] = useState(0)function handleClick(){setScore(score+1)}return (<div><p>月薪:{score}K</p><button onClick={handleClick}>点我升职加薪</button></div>)
}
②useContext:可以避免props层层传递的情况,方便共享数据。
import { createContext, useContext } from 'react';export function Section({ children }) {const level = useContext(LevelContext)return (<section className='section'><LevelContext.Provider value={level + 1}>{children}</LevelContext.Provider></section>)
}const LevelContext = createContext(0); // 默认值为0export function Heading({ children }) {const level = useContext(LevelContext);switch (level) {case 1:return <h1>{children}</h1>case 2:return <h2>{children}</h2>case 3:return <h3>{children}</h3>case 4:return <h4>{children}</h4>case 5:return <h5>{children}</h5>default:throw new Error('Invalid heading level')}
}export default function App() {return (<div><Section><Heading>主标题</Heading><Section><Heading>副标题</Heading><Heading>副标题</Heading><Heading>副标题</Heading><Section><Heading>子标题</Heading><Heading>子标题</Heading><Heading>子标题</Heading><Section><Heading>子子标题</Heading><Heading>子子标题</Heading><Heading>子子标题</Heading></Section></Section></Section></Section></div>)
}
③useReducer:结合useReducer和dispatch可以实现类似Redux的状态管理。
import {useReducer} from 'react'
export default function App(){function reducer(state, action){switch(action.type){case 'up':return state + 1case 'down':return state -1}}const cnts = 0//计数器const [state, dispatch] = useReducer(reducer, cnts)const handleIncre = () => dispatch({type:'up'})const handleDecre = () => dispatch({type:'down'})return (<div style={{padding:20}}><button onClick={handleDecre}>-</button><span> {state} </span><button onClick={handleIncre}>+</button></div>)
}
④useRef:引用之前的值、之前的标签、之前的组件
import {useRef,useState} from 'react'
export default function App(){const [count, setCount] = useState(0)const prevCount = useRef()function handleClick(){//记录更新之前的count值prevCount.current = countsetCount(count + 1)}return (<div style={{padding:20}}><p>最新的count:{count}</p><p>上一次的count:{prevCount.current}</p><button onClick={handleClick}>增加</button></div>)
}
⑤useEffect:主键加载时,可以设置一些“副作用”

后端的同学可以结合监视者设计模式来理解

import {useEffect,useState} from 'react'
export default function App(){const [count, setCount] = useState(0)//监听count值,当变化时,执行一些操作,[]里表示监听那些数据useEffect(()=>{console.log('count变化了...do somethings');},[count])function handleClick(){setCount(count + 1)}return (<div style={{padding:20}}><p>count:{count}</p><button onClick={handleClick}>增加</button></div>)
}
⑥useMemo:用于数据缓存,父组件的重新渲染会导致子组件的代码也重新执行,这时我们可以通过useMemo来缓存数据,通过[value]来指定当value值变化时,才会重新执行子组件的某个逻辑
import { useMemo, useState } from 'react'
/*useMemo:缓存值,当监听的值有变化时,才会重新执行逻辑-- 本案例只有当输入框中的数字有变化时,才会重新执行复杂逻辑
*/
function DoSomeDiffcult({ value }) {//缓存第一次的result值,后续只有当传入函数的value值变化时,才会重新执行逻辑,否则直接从缓存中取值返回const result = useMemo(() => {let result = 0console.log('执行系列复杂计算....');result =  value * 24124142return result;}, [value])return (<div><p>输入内容:{value}</p><p>经过复杂处理后的数据:{result}</p></div>);
}function App() {const [count, setCount] = useState(0)const [inputValue, setInputValue] = useState(3)return (<div style={{ padding: 20 }}><p>count的值为:{count}</p><button onClick={() => setCount(count + 1)}>点击更新</button><br/><br/><input type='number' value={inputValue} onChange={e => setInputValue(parseInt(e.target.value))}></input><DoSomeDiffcult value={inputValue} /></div>)
}export default App;
⑦useCallback:用于函数缓存,memo记忆子组件+useCallback,保证传入的函数是同一个,从而控制子组件不重新渲染
import { memo, useState, useCallback } from 'react'
/*useCallback: 缓存函数-- 通过useCallback保证传入的是同一个handleClick,防止每次父组件更新,子组件都被迫更新-- 当触发子组件的click事件时,才会更新
*/
const Button = memo(function({onClick}){console.log('button 被渲染了');return <button onClick={onClick}>子组件</button>
})function App() {const [count, setCount] = useState(0)const handleClick = useCallback(() => {console.log("点击按钮");},[]);return (<div style={{ padding: 20 }}><p>count的值为:{count}</p><button onClick={() => setCount(count + 1)}>点击更新</button><br/><br/><Button onClick={handleClick}></Button></div>)
}export default App;

2 实战篇

了解了React的核心概念之后,下面进入demo环节。通过我们学习的知识实现一个todoList代办列表。
全部代码:https://github.com/ziyifast/front-demo/tree/main/2-my-todo-list

最终项目结构:

在这里插入图片描述

2.1 创建项目

# 创建项目,然后根据提示设置自己所需要的内容
npx create-next-app@latest# 创建完成之后,cd 进入我们的项目,执行npm run dev启动项目
npm run dev 

在这里插入图片描述

2.2 分析&创建types&components

我们要实现一个代办事项

  1. types.ts:一个代办项包括它的内容text,它的状态completed,以及它的id。
  2. components:自定义所需组件
  • AddTodo.tsx:添加代办模块
  • TodoFilter.tsx:过滤模块(全部、已完成、未完成)
  • TodoItem.tsx:单个代办项(包含text、删除按钮、已完成按钮)
  • TodoList.tsx:页面主体(展示代办项)
  1. pages.tsx:组装组件,将自定义组件放入主页面
①types.ts
// 定义代办项
export interface Todo {id: number;text: string;completed: boolean;
}
②components:定义页面所需组件

创建components文件夹,在该文件夹下创建页面所需组件

  • AddTodo.tsx:添加代办模块
  • TodoFilter.tsx:过滤模块(全部、已完成、未完成)
  • TodoItem.tsx:单个代办项(包含text、删除按钮、已完成按钮)
  • TodoList.tsx:页面主体(展示代办项)
1. AddTodo.tsx:添加代办模块
import React, { useState } from "react"interface AddTodoProps {addTodo: (text: string) => void
}
export function AddTodo({addTodo}: AddTodoProps){const [text, setText] = useState('')//处理提交请求const handleSubmit = (e: React.FormEvent<HTMLFormElement>) =>{//阻止表单默认行为e.preventDefault()addTodo(text)//提交之后将输入框置空setText('')}return (<form onSubmit={handleSubmit}><input aria-label="新建代办"type="text" value={text} onChange={(e) => setText(e.target.value)}/><button type="submit">新建代办</button></form>)
}
2. TodoFilter.tsx:过滤模块(全部、已完成、未完成)
export default function TodoFilter({setFilter}:any){return (<div><button onClick={()=>setFilter('all')}>All</button><button onClick={()=>setFilter('completed')}>Completed</button><button onClick={() => setFilter('active')}>active</button></div>)
}
3. TodoItem.tsx:单个代办项(包含text、删除按钮、已完成按钮)
export function TodoItem({todo, toggleTodo, deleteTodo}:any) {return (<li style={{textDecoration: todo.completed ? 'line-through' : 'none'}}>{todo.text}<button onClick={() => toggleTodo(todo.id)}>切换</button><button onClick={() => deleteTodo(todo.id)}>删除</button></li>)
}
4. TodoList.tsx:页面主体(展示代办项)
import { Todo } from "@/types"
import { TodoItem } from "./TodoItem";interface TodoListProps {todos: Array<Todo>;deleteTodo: (id: number) => void;toggleTodo: (id: number) => void;
}export default function TodoList({ todos, deleteTodo, toggleTodo }: TodoListProps) {return (<ul>{todos.map(todo => (<TodoItem key={todo.id} todo={todo} deleteTodo={deleteTodo} toggleTodo={toggleTodo} />  ))}</ul>)
}
③page.tsx
"use client";
import Image from "next/image";
import styles from "./page.module.css";
import TodoFilter from "@/components/TodoFilter";
import TodoList from "@/components/TodoList";
import { AddTodo } from "@/components/AddTodo";
import { useState } from "react";
import { Todo } from "@/types";export default function Home() {//初始代办事项为空const [todos, setTodos] = useState<Todo[]>([])const [filter, setFilter] = useState('all')const addTodo = (text: string) => {const newTodoItem = {id: Date.now(),text,completed: false}setTodos([...todos, newTodoItem])}const deleteTodo = (id: number) => {setTodos(todos.filter(todo => todo.id !== id))}const toggleTodo = (id: number) => {setTodos(todos.map(todo => {if (todo.id === id) {todo.completed = !todo.completed}return todo}))}const getFilterTodo = () => {switch (filter) {case 'completed':return todos.filter(todo => todo.completed)case 'active':return todos.filter(todo => !todo.completed)default:return todos}}return (<div><h1>my-todo-list</h1><AddTodo addTodo={addTodo}></AddTodo><TodoList todos={getFilterTodo()} deleteTodo={deleteTodo} toggleTodo={toggleTodo}></TodoList><TodoFilter setFilter={setFilter}></TodoFilter></div>);
}
④效果

页面效果很简陋,主要给大家展示用法,后续大家可以引入第三方样式或者自定义样式来美化

# 进入并运行项目
cd 2-my-todo-list/
npm run dev 

在这里插入图片描述
页面效果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/508107.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Excel MATCH函数 两张顺序不同表格,统一排序

目录 一. 背景二. 添加辅助列,使用MATCH函数生成排序条件三. 效果 一. 背景 有如下图所示的两张表格&#xff0c;分别记录着同一批人的1月份和2月份的工资。表格A和表格B中的姓名列相同&#xff0c;工资列数据不同现在要求参考表格A中的姓名列对表格B中的数据进行排序&#xf…

C语言:预处理

C语言&#xff1a;预处理 预定义符号#define定义常量定义宏宏与函数对比 #操作符##操作符条件编译头文件包含库文件包含本地文件包含嵌套文件包含 预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //…

产品推荐 - 基于复旦微 JFM7K325T FPGA 的高性能 PCIe 总线数据预处理载板(100%国产化)

01 产品概述 PCIE711 是一款基于 PCIE 总线架构的高性能数据预处理 FMC 载板&#xff0c;板卡采用复旦微的 JFM7K325T FPGA 作为实时处理器&#xff0c;实现各个接口之间的互联。该板卡可以实现 100%国产化。 板卡具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1…

打造个人知识库-chatwithrtx接口研究

前言 之前安装了chatwithrtx&#xff0c;确实挺好用的。但是如果想用其对外提供服务的话&#xff0c;还需要研究是否能够提供api接口进行调用&#xff0c;所以今天来进行一下研究。 gradio介绍 web的访问是通过gradio框架进行开发的。在user_interface.py中可以发现如下引用 im…

ChatGPT 4.0使用之论文阅读

文章目录 阅读环境准备打开AskYourPDF进入主站 粗读论文直接通过右侧边框进行提问选中文章内容翻译或概括插图的理解 总结 拥有了GPT4.0之后&#xff0c;最重要的就是学会如何充分发挥它的强大功能&#xff0c;不然一个月20美元的费用花费的可太心疼了&#xff08;家境贫寒&…

Sora:引领A股市场的AI革命

OpenAI发布的文生视频模型Sora对A股市场产生了显著影响。Sora模型能够根据文本提示生成长达一分钟的逼真视频&#xff0c;这一技术突破在资本市场引起了广泛关注。Sora的发布导致相关概念股在A股市场上出现了显著上涨。例如&#xff0c;据报道&#xff0c;Sora发布后&#xff0…

【数据结构】_包装类与泛型

目录 1. 包装类 1.1 基本数据类型和对应的包装类 1.2 &#xff08;自动&#xff09;装箱和&#xff08;自动&#xff09;拆箱 1.2.1 装箱与拆箱 1.2.2 自动&#xff08;显式&#xff09;装箱与自动&#xff08;显式&#xff09;拆箱 1.3 valueOf()方法 2. 泛型类 2.1 泛…

MATLAB环境下基于图像处理的计算病理学图像分割(MATLAB R2021B)

人工智能是病理学诊断和研究的重要新兴方法&#xff0c;其不仅可用于病理形态数据分析&#xff0c;还可整合免疫组化、分子检测数据和临床信息&#xff0c;得出综合的病理诊断报告&#xff0c;为患者提供预后信息和精准的药物治疗指导。计算病理学是病理学与AI、计算机视觉等信…

Mistral AI 的大语言模型怎么样?

对用户来说&#xff0c;更多的选择没坏处&#xff1b;如果这个选择本身还很优质&#xff0c;那就更棒了。 对话 早上&#xff0c;我收到了 Mistral 发来的邮件&#xff0c;提示我拥有了访问 Le Chat 的权限。 我一时觉得很奇怪&#xff0c;什么是 Le Chat&#xff1f; 然后我才…

深度学习需要掌握哪些数学基础?

《深度学习的数学》这本书再合适不过了。作者罗纳德.T.纽塞尔&#xff08;Ronald T. Kneusel&#xff09;&#xff0c;拥有超过 20年的机器学习行业经验。 本书适合有一定深度学习基础、了解Python编程语言的读者阅读&#xff0c;也可作为用于拓展深度学习理论的参考书。 为什么…

STM32(8)NVIC编程

中断源由部分片上外设产生 在misc.h中找&#xff0c;杂项 配置NVIC GPIO和AFIO不能产生中断源&#xff0c;但能通过EXTI&#xff0c;由EXTI产生中断源 NVIC不需要开启时钟&#xff0c;因为NVIC模块位于内核内部&#xff0c;芯片一上电就能工作。 中断响应函数 中断向量表在启…

韦东山嵌入式Liunx入门驱动开发五

文章目录 一、驱动程序基石1-1 休眠与唤醒1-2 POLL机制1-3 异步通知(1) 异步通知程序解析(2) 异步通知机制内核代码详解 1-4 阻塞与非阻塞1-5 定时器(1) 内核函数(2) 定时器时间单位 1-6 中断下半部 tasklet 本人学习完韦老师的视频&#xff0c;因此来复习巩固&#xff0c;写以…