# 全局安装脚手架
npm i create-react-app -g
创建项目:
# project-name 项目名称
create-react-app react-demo
src/index.js:
// 导入 react [核心语法包]
import React from "react";
// 导入 react-dom [react操作DOM的模块包]
import ReactDOM from "react-dom";
// <h1 id='desc'>你好</h1>
// 1. 创建react虚拟DOM元素 React.createElement(标签名,属性,内容)
const h1 = React.createElement('h1', { id: 'desc' }, '你好')
// 2. 将react元素挂载到对应节点上 ReactDOM.render(渲染的react元素,挂载节点,回调)
ReactDOM.render(h1, document.getElementById('root'))
JSX: javascript xml 是React.createElement的语法糖 帮我们做了编译, 可以使创建元素更加简单,更加直观,提高开发效率。
// 语法点
// 1. 使用{变量/表达式} 渲染数据
// ===> 对象不能直接渲染
// ===> 布尔值渲染不出来, 但是作为判断是可以的
// 2. 标签必须要闭合(注意单标签)
// 3. 注释写法: {/* 注释内容 */}
// 4. 一些标签的属性发送了变化
// ===> class变成className
// ===> label的for属性 变成 htmlFor
// ===> 多个单词组成的属性要变成驼峰命名
// 5. 标签的嵌套一定要符合严格语法要求
// 6. 属性绑定 < 标签 属性={变量} 属性={'字符串'+变量} >
// 7. 一个JSX片段建议使用()包裹
// 8. 一个JSX片段必须只有一个根标签
// ===> <> 包裹元素 </>
// ===> <React.Fragment> 包裹元素 </React.Fragment>
JSX渲染数组 会将数组每个元素取出进行渲染
样式渲染:
// 语法:
// < 标签 style={ 样式描述对象 } />
// < 标签 style={ {css属性名:"css属性值"} } />
React 创建组件:
- 使用函数
function - 使用类
class
- 语法约定
- 函数名称
首字母必需大写,React 据此来区分组件和 HTML 元素 - 函数
必须有返回值,表示该组件的 UI 结构,如果不渲染任何内容可返回null
- 函数名称
回顾 class 语法定义类属性和函数,回顾 extends 语法继承父类:
// 回顾类的知识点
// ES5中, 定义类使用的是 构造函数 函数首字母大写
// ES6中, 定义类使用的是 关键字class
class Animal {
top = '我是动物类'
say = function () {
console.log('我会说话===动物类');
}
}
class Dog extends Animal {
// 类的成员属性
type = '狗类'
// 类的成员方法
skill = function () {
console.log('我会看家');
}
// 类的静态属性(不会变)
// static desc = '这是狗类的描述'
// // 类的静态方法
// static run = function () {
// console.log('狗会跑');
// }
}
Dog.desc = '这是狗类的描述111'
Dog.run = function () {
console.log('狗会跑111');
}
let d = new Dog()
console.log(d);
d.skill()
console.log('=====================');
// 静态属性和方法需要通过类名去调用
console.log(Dog.desc);
Dog.run()
类组件-定义状态:
- 定义
state属性定义组件状态,属于组件自己的数据,它的值是个对象。 - 使用
state的时候通过this去访问即可,例如:this.state.xxx。 - 数据发生变化,驱动视图更新。
// 一定要有render函数 返回JSX片段 会自动调用
// 状态数据定义在state属性里面
// state数据改变 render也会重新调用
快捷键:rcc
事件绑定用on事件名, 事件名第一个字母要大写
this指向的解决方式:
constructor() {
super()
// 方式2: 在构造函数里面使用bind将this绑定
this.fn3 = this.fn3.bind(this)
}
// 定义状态
state = {
count: 100
}
// 事件函数
fn1() {
console.log('fn1');
console.log(this); // undefined
}
fn2() {
console.log('fn2');
console.log(this); // 当前组件
}
fn3() {
console.log('fn3');
console.log(this); // 当前组件
}
fn4() {
console.log('fn4');
console.log(this); // 当前组件
}
// 方式4 定义事件函数的时候就定义成箭头函数
fn5 = () => {
console.log('fn5');
console.log(this); // 当前组件
}
render() {
return (
<div>
<h3>App组件</h3>
<p>count的数据是{this.state.count}</p>
<button onClick={this.fn1}>点击+10</button>
{/* 方式1: 模板里面使用bind将this绑定 */}
<button onClick={this.fn2.bind(this)}>点击+10</button>
{/* 方式2: 构造函数里面bind绑定 */}
<button onClick={this.fn3}>点击+10</button>
{/* 方式3: 模板里面定义箭头函数 箭头函数可以留存this的指向不变化 */}
<button onClick={() => { this.fn4() }}>点击+10</button>
{/* 方式4: 定义事件函数的时候就定义成箭头函数 */}
<button onClick={this.fn5}>点击+10</button>
</div>
)
}
既传参又获取事件对象:
// 定义状态
state = {
count: 100
}
// 事件函数
fn2(num, event) {
event.preventDefault()
console.log(event);
console.log(num);
console.log('fn2');
console.log(this); // 当前组件
}
fn4(num, event) {
event.preventDefault()
console.log(event);
console.log(num);
console.log('fn4');
console.log(this); // 当前组件
}
render() {
return (
<div>
<h3>App组件</h3>
<p>count的数据是{this.state.count}</p>
<a href="" onClick={this.fn2.bind(this, 10)}>点击+10</a>
<a href="" onClick={(event) => { this.fn4(20, event) }}>点击+20</a>
</div>
)
}
修改state数据:
// setState方法调用之后, 会让render函数重新执行, 实现页面更新
this.setState({ count: 200 })
// render里面不要写setState方法 否则会出现死循环
受控组件和非受控组件( 没有被state控制的表单原生认为是非受控组件 )
非受控组件表单绑定:
// createRef表示用于创建一个引用对象, 类似ref的作用
constructor() {
super()
// 1. 创建引用对象
this.mobileRef = createRef()
this.passwordRef = createRef()
}
// this.引用对象.current 表示获取到了对应的DOM节点
绑定: ref={this.mobileRef}
组件通信:
父直接在子上面传
const Hello = (props) => {
// 函数式组件, 形参是props数据
console.log(props);
return (
<div>
<h3>Hello</h3>
<p>{props.msg}==={props.num}</p>
{props.title}
</div>
)
}
export default class Hi extends Component {
render() {
console.log(this.props); // 父子通信的数据
console.log(this.props.state);
this.props.fn()
return (
<div>
<h3>Hi</h3>
<p>{this.props.desc}</p>
</div>
)
}
}
可以用解构直接传进去: <Item key={item.id} {...item} />
生命周期:
// 创建期: constructor==>render==>componentDidMount[挂载完成, 一般做ajax请求或者初始化插件, 类似vue的mounted]
// 更新期: render==>componentDidUpdate[每次数据state或props更新都会执行]
// 销毁期: componentWillUnmount[组件将要卸载时触发, 清除定时器]
// 实现插槽的2种方式:
// 方式1: 父子通信 传递JSX片段
// 方式2: 组件标签之间放内容, props.children访问
props校验:
// 定义校验的静态属性
List.propTypes = {
// 属性名: 校验函数
// 属性名: 校验函数.isRequired // 必须要传入
colors:PropTypes.array,
num:PropTypes.number.isRequired
}
List.defaultProps={
msg:'我是msg的默认值'
}
static propTypes = {
title:PropTypes.oneOfType([PropTypes.number,PropTypes.string]).isRequired,
sex:PropTypes.oneOf(['男','女'])
}
static defaultProps={
ok:'我是默认的ok'
}
Hooks:
// Hooks 只用在函数组件 提供状态
// 作用: useState是给函数组件提供状态
// 使用: useState(初始值)
// 返回 一个数组, 第一个元素时定义的状态, 第二个元素时修改数据的方法
const [msg, setMsg] = useState('你好Hooks')
// msg 是定义的状态数据变量
// setMsg 是修改状态的方法, setMsg( 新值 )
修改:
const changeList1 = () => {
list.splice(0, 1, 'haha')
// setList(list) 这样不更新, 地址没有改变
setList([...list])
}
useEffect:
// useEffect( ()=>{ 逻辑代码 },[变量] )
// 类似监听器的作用, 当变量发送变化的时候, 才会执行逻辑代码
useEffect(() => {
console.log("count的数值是:" + count);
document.title = `点了${count}次`
}, [count])
// useEffect( ()=>{ 逻辑代码 },[ ] ) 依赖空数组
// 类似 compentDidMount 挂载完成之后
useEffect(() => {
window.addEventListener('resize', () => {
console.log('尺寸调整了');
})
}, []) // 页面更新时
useEffect(() => {
console.log('发送请求');
}, []) // 页面一打开时
// useEffect 副作用
// 渲染之外的操作都称之为副作用
/* useEffect( ()=>{
逻辑代码
return ()=>{
销毁的时候要做的事情
}
},[])
// 类似componentWillUnMount
*/
// const [变量, 修改方法] = useState(初始值)
// 修改数据方法1: 修改方法( 新值 ) ====> 合并策略
// 修改数据方法2: 修改方法( 老值=>新值) ====> 每个都执行
路由:
import { HashRouter, NavLink, Route, Switch, Redirect } from 'react-router-dom'
// 路由模式组件: BrowserRouter(history模式路由) / HashRouter(hash模式路由) 顶层标签, 所有路由组件在其内部
// 导航链接组件: NavLink 导航用到, 涉及到高亮激活的 <NavLink to="/地址"></NavLink>
// 普通链接组件: Link 普通的跳转标签 <Link to="/地址"></Link>
// 路由映射组件: Route 建立组件和地址之间的关系
// ==>优先级 低 <Route path="/地址" component={组件}></Route>
// ==>优先级 高 <Route path="/地址"><组件/></Route>
// exact严格模式
// 匹配跳出组件 Switch 从上往下匹配, 匹配到了就跳出, 不继续匹配了
// 重定向组件 Redirect <Redirect to="/地址" />
// 导入页面组件
// import Home from './views/Home'
// import News from './views/News'
// import Product from './views/Product'
// import User from './views/User'
// import NotFound from './views/NotFound'
// import NewsDetail from './views/News/detail'
// import ProductDetail from './views/Product/detail'
// import Login from './views/Login'
// 路由懒加载
// React.lazy(() => import(组件路径))
导航守卫:
// 导航守卫 定义一个权限组件
const AuthRoute = (props) => {
if (localStorage.getItem('USER-TOKEN')) {
// 登录, 正常渲染
return <Route {...props}>{props.children}</Route>
} else {
// 未登录, 渲染Redirect
return <Redirect to="/login" />
}
}
路由信息钩子:
import {useParams,useHistory} from 'react-router-dom'
antd组件库:
表单:
{/* 登录表单 */}
{/* Form组件上的validateTrigger属性是设置表单校验的时机, 默认是onChange变化的时候 */}
{/* Form组件上的initialValues={{key:val,key2:val2}} 表示表单的初始值 */}
{/* Form.Item组件上的valuePropName是取哪个属性的值作为数据 默认是value */}
<Form validateTrigger={["onChange","onBlur"]} autoComplete="off">
<Form.Item name="mobile" rules={formRuels.mobile}>
<Input prefix={<UserOutlined/>} placeholder="请输入手机号" />
</Form.Item>
<Form.Item name="code" rules={formRuels.code}>
<Input prefix={<LockOutlined/>} placeholder="请输入验证码" />
</Form.Item>
<Form.Item name="isAgree" valuePropName="checked">
<Checkbox>我已阅读并同意「用户协议」和「隐私条款」</Checkbox>
</Form.Item>
<Form.Item>
<Button type="primary" block>
登录
</Button>
</Form.Item>
</Form>
本文介绍了React的基础知识,包括全局安装脚手架、创建项目、JSX语法、组件创建、事件绑定、状态管理和生命周期。讲解了如何使用函数和类创建组件,以及如何处理this指向问题。还涉及了React中的样式渲染、组件通信、受控与非受控组件的概念,最后探讨了Hooks的使用,如useState和useEffect,以及路由的基本应用。
1165

被折叠的 条评论
为什么被折叠?



