一文让你快速上手React18,最直白知识点总结
Excerpt
一文让你快速上手React18,最直白知识点总结 0、环境配置 1、使用 create-react-app 快速创建开发环境 npx create-react-app my-app --templat
一文让你快速上手React18,最直白知识点总结
本文是个人自己学习
React
后的基础知识总结,是为了加深印象,以及后续项目中某些知识点记忆不清晰,能够快速查找到实用案例;希望对学习React的朋友们带来些许帮助,谢谢~
1、JSX插值表达式
jsx
1-1、{/* 🔔// string number 正常显示 */}
<h1>{'hello React'}</h1>
<h1>{73}</h1>
1-2、{/* null undefined boolean 🔔不显示*/}
1-3、{/* 💥对象不能直接放在插值表达式中,会报错 */}
ex: const obj = {name:'zs'}
{obj} => 报错
{obj.name} => 🆗
1-4、{/* 🔔 数组中的每项元素,都会当做一个dom节点渲染出来 */}
// 数组
const list = [<div>1</div>, <div>2</div>, <div>3</div>]
<h1>{list}</h1> => 1
2
3
1-5、{/* 1. 💥 函数本身也属于对象,函数本身不能放在插值表达式中 */}
{/* 通常放函数的调用,函数的返回值也不能对象 */}
{hello()}
1-6、{/* 三元 */}
<h2>{isShow ? 'show' : '不显示'}</h2>
1-7、{/* 逻辑 */}
<h3>{isShow && '显示'}</h3>
1-8、{/* 💥 JSX本身也可以当做表达式放在插值符号中,往往配合其它的使用方式 */}
<h4>{<span>123</span>}</h4>
2、条件、列表渲染
if else 语句
javascriptfunction loadData() { if (isLoading) { return <h1>加载中...</h1>; } else { return <div>加载完毕</div>; } } {loadData()}
三元表达式
text{isLoading ? <h1>加载中...</h1> : <h3>加载完毕</h3>}
逻辑运算符
text{isLoading && <h1>加载中...</h1>} {!isLoading && <div>加载完毕</div>}
列表渲染,类似v-for
javascript// 方法一 const list = ['萝卜', '白菜', '橘子']; {list.map((item, index) => { // render 内部 return ( <h1 // 💥key的作用:和v-for的key作用一模一样,都是提高更新效率 // 🔔key的口诀:有id 用id ,没id用索引 key={index} > {item} </h1> ); })} // 方法二 const list = ['萝卜', '白菜', '橘子']; const listNode = list.map((item, index) => { return <h1 key={index}>{item}</h1>; }); {listNode} // render 内部
3、行内样式
stylus
语法:style= {{css属性名:属性值}}
{/* 💥 React中不支持css属性连字符, 👍要求使用驼峰 */}
{/* 💥 px单位可以省略,值直接写数字 */}
<h1 style={{ color: 'red', fontSize: 12 }}>我想红</h1>
4、组件类型(函数式组件/类组件)
函数式组件
javascript// 基本要求 // 1.1 组件名称首字母必须大写 // 1.2 函数必须返回一段JSX,如果不需要渲染任何内容,返回一个null // ✅ 组件 function Hello() { return null; } {/* 使用上:💥React对大小写敏感 */} <Hello></Hello>
类组件
javascript// 基本要求 // 1. 组件名字必须大写字母开头 // 2. render函数中必须返回一段JSX,如果不需要渲染任何内容,返回null // 3. 必须有render函数,否则报错,render函数类似函数式组件的语法 // ✅ 组件 class Hello extends React.Component { render() { return null; } } {/* 使用上:💥React对大小写敏感 */} <Hello></Hello>
- extend继承
javascript// class的作用: 创建对象 // 💥 属性 = 值 class Programer { gender = '男'; writeCode() { console.log('我代码写的贼6 -----> '); } } // extends的作用:基础父类(爸爸)所有的属性和方法 // 目的:复用相同的属性和方法,减少创建对象时消耗的内存 class FrontEnd extends Programer { // 自动获得爸爸所有的属性和方法 name = 'fe'; }
5、状态 state
javascript
// 基本语法:state = {数据变量名: 值}, 可以声明多个数据
state = {
count: 100,
msg: 'hello React',
};
// 使用:获取state: 通过this.state.xxxx访问数据
// 💥 this 指向组件实例对象,与Vue类似
render(
return (
<h1>
我是App - {this.state.count} - {this.state.msg}
</h1>
);
)
6、事件绑定
javascript
// 基础语法:on+大写驼峰事件名 = {函数名}
// 常见的两种写法:
// 👍1. 少量代码: 使用一个箭头函数
onClick={() => alert('123')}
onClick={this.handleClick}
// 注意:
// 1. 不能加():❌ onClick={this.handleClick()}
// 事件必须接受一个函数,而且要放在花括号中
// 2. 不能放在字符串中:❌onClick="alert('123')"
7、获取事件对象
javascript
// 获取事件对象 event
<a
// 💥 绑定事件的默认形参就是事件对象event, 类似Vue,
// 1. onClick={(e) => e.preventDefault()}
href="http://www.baidu.com"
onClick={this.handleClick}
>
点我跳百度
</a>
// 多行代码写法
handleClick(e) {
e.preventDefault();
console.log('come here -----> ');
}
8、事件传值
javascript
// 基础语法
onClick={(e) => this.handleClick(e, 2)}
// 自定义事件函数
handleClick(e, num) {
// 能够接收到外部传来的值
console.log('num, e -----> ', num, e);
}
9、修改状态 setState
javascript
// 基础语法:setState({更新的数据: 新的值})
this.setState({ msg: this.state.msg + '123', count: this.state.count + 100 });
// 💥注意:
// React中不可变数据-不允许直接修改state
this.state.count += 100;
this.setState({ count: (this.state.count += 100) });
10、不可变数据(即数组不可用方法修改state)
javascript
// 不可变数据: 不能使用会修改原数据的方法
// 如:push 、concat
// 如:this.state.count++
// ✅setState 新值覆盖旧值
this.setState({ list: [...this.state.list, 5] });
// 注意:
❌ this.state.list.push(5);
11、受控组件
受控组件 => 表单操做方式
javascript<input type="text" value={this.state.msg} // 💥React对表单的事件特殊处理,以后,所有表单的改变事件都用onChange onChange={(e) => { console.log('e.target.value -----> ', e.target.value); this.setState({ msg: e.target.value }); }} // 💥 React中的失焦事件为onBlur onBlur={(e) => { console.log('e.target.value -----> ', e.target.value); }} /> //
常见受控组件
javascriptstate = { name: 'zs', intro: '', city: '4', isSingle: true, }; // input <input type="text" value={name} onChange={this.handleChangeName} /> // textarea 文本域 <textarea value={intro} onChange={this.handleChangeIntro}></textarea> // select 下拉选择 <select value={city} onChange={this.handleChangeCity}> <option value="1">北京</option> <option value="2">上海</option> <option value="3">广州</option> <option value="4">深圳</option> </select> // checkbox 单选框 <input type="checkbox" checked={isSingle} onChange={this.handleChangeSingle} />
12、ref(获取dom元素、组件实例对象)
javascript
// 1. 创建 ref
iptRef = React.createRef();
childRef = React.createRef();
// 2. 绑定给dom元素或者组件
<input
type="text"
// 2. 绑定给dom元素或者组件
ref={this.iptRef}
/>
<Child ref={this.childRef}></Child>
<button onClick={this.handleClick}>点我访问input元素,主动让input获得焦点</button>
// 3. 通过ref对象.current属性来访问
this.iptRef.current.focus();
13、props 组件通讯
基本使用
javascript{/* 1. 传递数据: 给标签加上标签属性和值 */} <Child name="zs123" age={18123} gender={'xxxx'}></Child> // 函数式组件:通过形参接收props function Child({ name, age } = props) { return ( <h1> 我是子组件 - {name} -{age} </h1> ); } // 类组件:通过this.props接收 class Child2 extends React.Component { render() { const { name, age } = this.props; return ( <div> <h1>{name}</h1> <h1>{age}</h1> </div> ); } }
props的三个特点
javascript1. props不必先定义后使用 2. props可以传递任意数据类型 number string null undefined boolean object 🔔 function JSX 3. props是只读的 - 类似vue中的单项数据流(修改需要调用父组件内的方法修改)
父传子
javascript// 父组件 state = { money: 1000, }; // 父传子 <Child money={this.state.money}></Child> // 子组件接收展示 class Child extends React.Component { render() { const { money } = this.props; return ( <div> <h1>爸爸给我钱了: {money} </h1> </div> ); } }
子传父
javascript// 父组件内部定义修改state的方法 // 1. 父组件内定义一个函数 handleCost = (num) => { console.log('num -----> ', num); this.setState({ money: this.state.money - num }); }; // 父传子 <Child money={this.state.money} // 2. 通过props传函数给子组件 handleCost={this.handleCost} ></Child> // 子组件:调用父组件传来的函数 <button onClick={() => handleCost(8000)}>点我花爸爸的钱</button>
兄弟通信
// 整体思路 兄弟组件通信,需要设计一个双方共同的父组件,然后数据及函数都由父组件集体管理,将父组件的state及fun传给兄弟组件,最终兄弟组件都是调用集体父组件的方法及state来达到通信的目的;
Context 跨组件通信
javascript// 1. React.createContext创建上下文, 解构出两个组件 Provider(提供者)Consumer(消费者) const { Provider, Consumer } = React.createContext(); // 2. 使用Provider组件,传数据: 设置value属性传数据 -- 包住后代 <Provider value="hello 我跨组件而来" > <Son></Son> // 子组件 </Provider> // 3. 使用Consumer组件,接收数据 {/* 💥 接受一个函数,返回需要返回一端JSX,形参就是Provider传来的数据 */} <Consumer> // 在孙组件之内 {(data) => { return <h1>我是Consumer - {data}</h1>; }} </Consumer> // 优缺点: 缺点:🔔增加组件的嵌套解构,难以阅读和理解 优点: 1. 🔔是React自带的跨组件通信方案,不需要额外下包 2. 第三方的包喜欢用这个,减少体积 场景🔔: 1. 多语言切换 2. 一键换色
14、props深入使用(插槽、校验)
childre(类似vue的插槽)
插槽的定义:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式
javascript// 第一步设置插槽组件 function Child({ children }: any) { return <h1>{children}</h1> } // 第二步 {/* 数组、原始数据类型 */} <Child>{[1, 2, 3, 4]}</Child> {/* 💥函数 */} <Child2> {() => { return <i>我是children传来的函数</i> }} </Child2> {/* 💥JSX */} <Child> <ul> <li>123</li> <li>456</li> </ul> </Child>
childre模拟 匿名插槽&具名插槽&作用域插槽
javascript// 匿名插槽 // 父组件内: <Child>{this.state.msg}</Child> // 子租件: class Child extends Component { render() { console.log('this -----> ', this); return <h1>Child子组件 - {this.props.children}</h1>; } } // 具名插槽 // 父组件内: <ChildHasName> {{ header: '蜀道难', footer: '难于上青天', }} </ChildHasName> // 子组件内: class ChildHasName extends Component { render() { return ( <div> <header>显示header: {this.props.children.header}</header> <footer>显示footer: {this.props.children.footer}</footer> </div> ); } } // 作用域插槽 // 父组件内: <ChildScope> {(data) => { return ( <ul> {data.map((item) => { return <li key={item}>{item}</li>; })} </ul> ); }} </ChildScope> // 子组件: class ChildScope extends Component { state = { list: ['苹果', '橘子', '香蕉'], }; render() { return <h1>Child子组件 - {this.props.children(this.state.list)}</h1>; } }
利用props校验
javascript// 1. 导入包props-type,提供类型 安装:npm install prop-types --save import PropTypes from 'prop-types'; // 2. 给组件设置规则对象 // 💥 组件名.propTypes = { 规则} Child.propTypes = { msg: PropTypes.string.isRequired, list: PropTypes.array, person: PropTypes.object, isShow: PropTypes.bool, handleClick: PropTypes.func, // 💥 JSX title: PropTypes.element, zs: PropTypes.shape({ name: PropTypes.string, age: PropTypes.number, }), }; // 3. 组件无需额外操作,父组件传值时需要按照规则传值 class Child extends React.Component { render() { return <div></div>; } }
defaultProps 默认值、
javascript// 第一步 设置defaultProps 默认值 Child(Son).defaultProps = { msg: 'hello Child', }; // 第二步 组件内用 props 获取 class Child extends React.Component { render() { return <div>{this.props.msg}</div>; } } // 类组件 function Son({ msg = 'hello Son' }) { return <h1>{msg}</h1>; } // 函数组件
static关键字
javascript// 类内部使用 static 关键字之后不会被子类继承,也不会初始化到实例对象中 // 使用 class Child extends React.Component { static propTypes = { msg: PropTypes.string.isRequired, list: PropTypes.array, person: PropTypes.object, isShow: PropTypes.bool, handleClick: PropTypes.func, // 💥 JSX title: PropTypes.element, zs: PropTypes.shape({ name: PropTypes.string, age: PropTypes.number, }), }; static defaultProps = { hello: '123', }; render() { return <div>{this.props.hello}</div>; } }
15、React 的生命周期
详细讲述React生命周期文章地址:juejin.cn/post/696618…
javascript
1. 挂载阶段 -
1.1 constructor: 创建时,对标vue中的 created
💥 早期声明state和ref,现在都简写
1.2 render:渲染dom
1.3 componentDidMount: 挂载后,对标vue中的mounted
💥 发请求、最先能够获取DOM、定时器、绑定事件
2. 更新阶段
2.1 render: 重新渲染dom
2.2 compoentDidUpdate:更新后,对标vue中的updated
💥 可以获取到更新后的值,常用来做缓存
3. 卸载阶段 -
3.1 componentWillUnMount
💥 做清除的动作,如:清除定时器、取消监听的事件
执行次数:
constructor和componentDidMount只会执行一次
componentWillUnMount只会执行一次
16、Hooks (重要)
16-1、useState基本使用
javascript
// 1. 导入 useState钩子函数: 声明状态
import React, { useState } from 'react';
// 2. 调用钩子函数
const [count, setCount] = useState(100);
// count 等价于 this.state.couont
// setCount等价于this.setState({couont: xxx})
// 3、使用
return (
<div>
<h1>{count}</h1>
<button
onClick={() => {
setCount(count + 1);
}}
>
点我加+1
</button>
</div>
);
16-2、useState注意事项
javascript
// 1. useState可以多次调用,声明多个状态
const [count, setCount] = useState(100);
const [msg, setMsg] = useState('hello React');
// 2. useState可声明任意数据类型
const [list, setList] = useState([1, 2, 3]);
const [person, setPerson] = useState({ name: 'zs', age: 18 });
// 3. 更新状态,还是新值覆盖旧值
setPerson({ ...person, name: 'ww' });
// ❌person.name = '王五';
16-3、Hooks的三个使用限制
javascript
// 1. hooks不能放在if语句中
if (false) {
// 💥React 是根据useState调用顺序,保证每个状态的值分配。React要求调用顺序永远不变
const [hello, setHello] = useState('123');
}
// 2. 不能放在for语句中
for (let index = 0; index < list.length; index++) {
const [hello, setHello] = useState('123');
}
// 3. 普通函数中不能使用hooks
function hello(params) {
const [state, setState] = useState('xxxx');
return null;
}
16-4、受控组件
javascript
// 1. 声明state
const [value, setValue] = useState('');
// 2. 控制value
<input
type="text"
value={value}
// 💥 绑定方法没有this了
onChange={handleChange}
/>
// 3. 声明方法用const
const handleChange = (e) => {
setValue(e.target.value);
};
16-5、useEffect基本使用
javascript
// 第一步 引入 useEffect
import React, { useState, useEffect } from 'react';
// 第二步 导入useEffect钩子函数: 会自动执行
// 语法: useEffect(回调函数); 回调函数中可以获取到更新后的值
useEffect(() => {
document.title = count;
});
16-6、useEffect模拟生命周期
javascript
// 1. 第二个参数为数组:空数组时代表的是挂载时。等价于componentDidMount
useEffect(() => {
console.log('我是挂载时的钩子函数,只会执行一次 -----> ');
document.title = count;
}, []);
// 2. 第二个参数为数组:数组内有依赖项(状态)时,
// 💥代表的是挂载时和更新时二合一, 类似Vue中的watch属性,开启了immediately
// 💥等价于componentDidMount 和 componentDidUpdate 二合一
useEffect(() => {
console.log('我是更新时的钩子函数 -----> ');
document.title = count;
}, [count]);
// 3、通过返回一个函数,模拟卸载时的生命周期
// 语法: useEffect回调函数内,返回一个函数,这个函数就是卸载时会自动执行的钩子函数
useEffect(() => {
return () => {
console.log('我要被卸载掉了 -----> ');
};
}, []);
16-7、useEffect监听多个状态
javascript
// 第一种 合并写法,需要根据多个状态的值,进行计算
useEffect(() => {
document.title = count + msg;
}, [count, msg]);
// 第二种 分开监听,不需要使用多个状态计算
useEffect(() => {
console.log('count -----> ', count);
}, [count]);
useEffect(() => {
console.log('msg -----> ', msg);
}, [msg]);
16-8、useEffect挂载与卸载综合写法
javascript
useEffect(() => {
const fn = () => {
console.log('浏览器窗口被调整了');
};
// 2. 同一个逻辑的挂载和卸载,合在一个useEffect里起来写
window.addEventListener('resize', fn);
return () => {
window.removeEventListener('resize', fn);
};
}, []);
16-9、useEffect 与 axios 请求
javascript
// 第一步 封装一个异步函数
useEffect(() => {
loadData();
}, []);
// 第二步 声明函数,请求回值并赋值
const loadData = async () => {
const res = await getChannelsAPI();
setList(res.data.channels);
};