本文主题: 掌握 React.js 项目搭建和基础用法
包括: React 的发展过程 | React 项目创建 |
React 基础能力: 组件 | State | Props | 组件通信 | 条件渲染 | 列表渲染
一、React 浅析
1.1 传统方式下前端是如何构建用户界面的?
JS本质 - 浏览器脚本
- JS 可以去操作 DOM, 可以去增删改查 DOM。
- JS 是一种可以操作DOM的动态语言。
1.2 基于 JavaScript 创建 DOM
任意一种标签元素, 都可以通过一个 JS 的函数来创建。封装一系列方法来完成该功能。
createElemet 的实现方式
function createElement(tag, attrs = {}, ...children) {
// 创建一个新元素
const element = document.createElement(tag);
// 设置元素的属性
for (let key in attrs) {
if (key.startsWith('on') && typeof attrs[key] === 'function') {
// 如果属性是一个事件监听器 (如 'onclick')
element.addEventListener(key.substring(2).toLowerCase(), attrs[key]);
} else if (key === 'style' && typeof attrs[key] === 'object') {
// 如果属性是样式对象
Object.assign(element.style, attrs[key]);
} else {
// 其他属性
element.setAttribute(key, attrs[key]);
}
}
// 添加子元素
children.forEach(child => {
if (typeof child === 'string') {
// 如果子元素是文本节点
element.appendChild(document.createTextNode(child));
} else if (child instanceof Node) {
// 如果子元素是 DOM 节点
element.appendChild(child);
}
});
return element;
}
// 使用示例
const myElement = createElement(
'div',
{ id: 'myDiv', class: 'container', style: { color: 'red', backgroundColor: 'black' }, onclick: () => alert('Hello!') },
createElement('h1', {}, 'Hello World!'),
'Some text here',
createElement('p', {}, 'This is a paragraph.')
);
document.body.appendChild(myElement);
1.3 按照这种逻辑我们是不是可以这样 - React 代码
<div id="app">
<h1>Hello!</h1>
<h2>This is</h2>
<h3>Me</h3>
</div>
createElement("div",{id:"app"},
createElement("h1",{},"Hello!")
createElement("h2",{},"This is<")
createElement("h3",{},"Me")
)
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
</header>
</div>
);
}
export default App;
// babel/preset-react
function App() {
return React.createElement("div", {
className: "App"
}, React.createElement("header", {
className: "App-header"
}, React.createElement("img", {
src: logo,
className: "App-logo",
alt: "logo"
}), React.createElement("p", null, "Edit ", React.createElement("code", null, "src/App.js"), " and save to reload.")));
}
export default App;
1.3.1 使用 babel 转换代码: babeljs.io/ try it out
1.4 对比分析React.createElement和我们的createELement有什么区别?
1.5 前端在干什么?
用户交互 → 页面更新
useEffect(); // 用户刷新
@click → handleClick → this.data.xxx = 'xxxx' → useState/dispatch
1.6 React 的灵活性
vue 中的 for 循环
<template v-for="item in list"></template>
react
{
list.map(item=> <span />)
}
二、创建 React 工程
npx create-react-app demo-app
npx create-react-app demo-app-ts --template typescript
npm run eject
三、React 的基础能力
3.1 子父组件
组件首字母大写
-
从界面的视角看
- Class 组件渲染的是 render 函数中的 return 的内容
- Function 组件渲染的是函数本身返回的内容
3.2 State 和 Props
在 react 中, 有一个概念叫 state。
-
如果我有一个数据, 我期望 数据改变时 去触发界面更新。
- 我要把数据定义为 State
- 我要使用特定的方法更新这个 State
3.2.1 类组件
setState
类组件上要使用 setState 方法
- State 的值互相不影响
- 第二个参数是一个 cb , 能拿到最新的 State
受控组件 Input 双向绑定
import React, {Component} from 'react'
// 类组件
export default class ClassCom extends Component {
// 定义 State
// 方法1: state = {}
// 正规写法 constructor
constructor(props){
super(props)
this.state = {
number: 0,
message: "Hello Tong"
}
}
handleClick = (type) => {
if(type === 'plus'){
this.setState({
number: this.state.number + 1
}, ()=>{
console.log('number in handleClick cb', this.state.number) // 最新的值
})
} else if(type === 'minus') {
this.setState({
number: this.state.number - 1
})
}
console.log('number in handleClick', this.state.number) // 没有立马更新,用cb拿到最新值
}
handleChange = (e)=>{
this.setState({
message: e.target.value
})
}
render(){
const {message,number} = this.state
return (
<div>
<h2>类组件 State的用法</h2>
<h3>message: {message}, number {number}</h3>
{/* 受控组件 期望 input value 和 message 一起 */}
<input type="text" value={message} onChange={this.handleChange} />
<button onClick={this.handleClick.bind(this,'plus')} >number 加1</button>
<button onClick={this.handleClick.bind(this,'minus')} >number 减1</button>
</div>
)
}
}
3.2.2 函数组件
useState
[state,dispatch] = useState(initState) useState 签名
-
State 作为组件的状态, 提供给 UI 渲染视图
-
dispatch 用户修改 State 的方法, 同时触发组件更新
- Dispatch参数 可以是函数, 可以不是, 如果是函数, 就更新为函数执行的结果, 如果不是, 直接更新为值。
- initstate: 初始值, 可以传, 也可以不传
3.2.3 Props
子父组件传值的工具
// APP.JSX
import { useState } from 'react';
import './App.css';
import ClassCom from './basic/ClassCom';
import FuncCom from './basic/FuncCom';
function App() {
const [count, setCount] = useState(1024)
const handleClick = ()=>{
setCount(count => count+1)
}
return (
<div className="App">
{/* 父组件向子组件传值 */}
<ClassCom name="我是类组件" />
<FuncCom name="我是函数组件" count={count} onClick={handleClick} setCount={setCount} />
</div>
);
}
export default App;
// FuncCom.JSX
import React, { useState } from 'react';
// 函数组件
export default function FuncCom({name,count,onClick,setCount}) {
// const arr = useState() => [S, Dispatch] = useState<S>(initialState: S | (() => S))
const [number, setNumber] = useState(_=>0)
const [message, setMsg] = useState("Hello React")
const handleClick = (type) =>{
if (type === 'plus') {
setNumber(number+1)
} else {
setNumber(number-1)
}
}
const handleChange = (e)=> {
setMsg(e.target.value)
}
return (
<div>
<p>Name: {name}</p>
<p>Count: {count}</p>
<h2>函数组件 UseState的用法</h2>
<h3>message: {message}, number {number}</h3>
{/* 受控组件 期望 input value 和 message 一起 */}
<input type="text" value={message} onChange={handleChange} />
<button onClick={handleClick.bind(this,'plus')} >number 加1</button>
<button onClick={handleClick.bind(this,'minus')} >number 减1</button>
<button onClick={()=>onClick?.()} >修改count</button>
<button onClick={()=>setCount(v=>v+1)} >修改count</button>
</div>
)
}
// ClassCom.JSX
import React, {Component} from 'react'
// 类组件
export default class ClassCom extends Component {
// 定义 State
// 方法1: state = {}
// 正规写法 constructor
constructor(props){
super(props)
this.state = {
number: 0,
message: "Hello Tong"
}
}
handleClick = (type) => {
if(type === 'plus'){
this.setState({
number: this.state.number + 1
}, ()=>{
console.log('number in handleClick cb', this.state.number) // 最新的值
})
} else if(type === 'minus') {
this.setState({
number: this.state.number - 1
})
}
console.log('number in handleClick', this.state.number) // 没有立马更新,用cb拿到最新值
}
handleChange = (e)=>{
this.setState({
message: e.target.value
})
}
render(){
const {message,number} = this.state
return (
<div>
<p>{this.props.name}</p>
<h2>类组件 State的用法</h2>
<h3>message: {message}, number {number}</h3>
{/* 受控组件 期望 input value 和 message 一起 */}
<input type="text" value={message} onChange={this.handleChange} />
<button onClick={this.handleClick.bind(this,'plus')} >number 加1</button>
<button onClick={this.handleClick.bind(this,'minus')} >number 减1</button>
</div>
)
}
}
3.3 条件渲染和列表渲染
import React from 'react';
export default function Render() {
const list = ['山东','山西','河南','河北']
return (
<div>
<div>========</div>
<div>{list.length>0 ? '地名' :'nothing'}</div>
<ul>
{
list.map(item=><li key={item}>{item}</li>)
}
</ul>
<div>========</div>
</div>
)
}
相关网站
Create React App 中文文档: create-react-app.bootcss.com/
React 官网: react.dev/
React 中文官网: react.docschina.org/