类组件:
js
import { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
message: "xxxxx",
};
}
render() {
return (
<div>
<div>{this.state.message}</div>
</div>
);
}
}
export default App;
js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
//react18
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
this指向问题
cli(){ console.log(this)}
默认情况下this是undefined。
在正常的dom操作中监听点击事件,监听的函数的this是节点对象。
而react并不是直接渲染成真实dom,它本质上是一个React的Element对象。在监听的时候,函数并没有绑定this,所以默认情况想就是一个undefined。
直接调用相当于默认调用
可以通过bind给它绑定this,render里面有this,指向组件实例。
js
add(){
console.log(this)
}
render(){
console.log(this)
return (
<div>
<button onClick={this.add.bind(this)}>+</button>
</div>
)
}
直接在html中绑定不太方便,可以在constructor中提前绑定
js
constructor(){
this.add = this.add.bind(this)
}
add(){
console.log(this)
}
render(){
return (
<div>
<button onClick={this.add}>+</button>
</div>
)
}
还有更简单的方法使用箭头函数
js
//setState简短说明
//setState继承自Component,
//调用setState后,会将state中的xxx的值修改掉,然后自动重新执行render函数
add(){
console.log(this)
this.setState({
})
}
render(){
return (
<div>
<button onClick={()=>this.add()}>+</button>
</div>
)
}
jsx
jsx是js的拓展语法,也在许多地方成为JavaScript XML。
jsx顶层只能有一个根元素,jsx中的标签可以是单标签,也可以是双标签。
jsx嵌套变量作为子元素
当变量为Number,String,Array时,可以直接显示。
当变量为null,undefined,boolean时,内容为空,如果需要显示的话可以将它们转换为字符创,例如使用toString
当变量为Object时,不能作为子元素
js
class App extends Component {
constructor() {
super();
this.state = {
message: "xxxxx",
age: 18,
address: ["!1", "222"],
isSelected: true,
test: " ",
// test: null, test:undefined
};
}
render() {
const { message, age, address, isSelected, test } = this.state;
return (
<div>
<div>{message}</div>
<div>{age}</div>
<div>{address[0]}</div>
<div>{isSelected.toString()}</div>
<div>{test}</div>
</div>
);
}
}
当变量为Object时
使用表达式
js
class App extends Component {
constructor() {
super();
this.state = {
message: "xxxxx",
age: 18,
address: ["!1", "222"],
isSelected: true,
test: null,
obj: {
name: "111",
age: 19,
},
};
}
address() {
return <span>test</span>;
}
render() {
const { message, age, address, isSelected, test, obj } = this.state;
if (isSelected) {
this.setState({
obj: {
age: 100,
},
});
}
return (
<div>
<div>{message}</div>
<div>{age}</div>
<div>{address[0]}</div>
<div>{isSelected.toString()}</div>
<div>{test}</div>
<div>{Object.keys(obj)[0]}</div>
{/* 使用表达式*/}
<div>{19 - 1}</div>
<div>{isSelected ? "true" : "false"}</div>
<div>
{[1, 2, 3].map((item) => {
return <li>{item}</li>;
})}
</div>
<div>{obj.age}</div>
<>{this.address()}</>
</div>
);
}
}
绑定 title,src,href,class,style
js
this.state = {
title: "xxx",
href: "https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-image",
url: "https://img-blog.csdnimg.cn/direct/38f2d0b33be2462796e2a123165e3fd8.png",
};
render() {
const { title, href, url } = this.state;
return (
<div>
<h1 title={title}>111</h1>
<a href={href}>a</a>
<img src={url} />
</div>
);
}
绑定className,style
js
render() {
const className = `aaa ${isSelected ? "active" : ""}`;
const classList = ["aa", "bb"];
classList.push("vvv");
return (
<div>
<div className={className}>11</div>
<div style={{ fontSize: "20px", color: "red" }}>www</div>
<div className={classList.join(" ")}></div>
</div>
);
}
事件的绑定
事件名使用小驼峰命名,通过{}传入一个事件处理函数,这个函数会在事件发生时被执行
<button onClick={this.add.bind(this)}>+</button>
传递event和其他参数
js
class App extends Component {
constructor() {
super();
this.state = {
};
}
add(event, age, num) {
console.log(event);
console.log(age, num);
}
render() {
return (
<div>
<button onClick={this.add.bind(this, "xx", 19)}>1</button>
<button onClick={(event) => this.add(event, "zzz", 11)}>2</button>
</div>
);
}
}
使用bind绑定的 event是最后一个
条件渲染
条件渲染的方式:
- 条件判断
- 三元运算符
- 与运算符&&
使用if条件判断
js
render() {
let ele;
const { isShow } = this.state;
if (isShow) {
ele = <h1>show</h1>;
} else {
ele = <h1>hidden</h1>;
}
return (
<div>
<span>{ele}</span>
<button onClick={(event) => this.add(event, "zzz", 11)}>2</button>
</div>
);
}
三元运算符和与运算符
js
<div>
<span>{isShow ? ele : "test"}</span>
<span>{isHidden + "" && "---11"}</span>
</div>
/* 在 JavaScript 中,对 undefined 变量使用 && 运算符可能会导致将整个表达式的结果视为假值。
这是因为在逻辑运算中,&& 运算符是一个短路逻辑运算符,如果左侧表达式的值为一个假值(例如 false、null、undefined、0、空字符串等),
那么整个表达式会立即返回左侧表达式的值,而不再计算右侧表达式。
如果想要确保对 undefined 变量进行逻辑运算时的预期行为,可以先将变量转换为字符串或者使用其他方法来处理。
*/
//模拟v-show
<div style={{display: isShow ? "block" : "hidden"}}> </div>
列表展示
使用map渲染列表
js
class App extends Component {
constructor() {
super();
this.state = {
list: [
{
id: 1,
name: "111",
},
{
id: 2,
name: "222",
},
{
id: 3,
name: "333",
},
{
id: 4,
name: "444",
},
],
};
}
render() {
const { list } = this.state;
return (
<div>
{list.map((item) => {
return <div key={item.id}>{item.name}</div>;
})}
</div>
);
}
}
export default App;
// jsx--ReactElement-真实dom
类组件
类组件的名称以大写字符开头,继承自React.Component,必须实现render函数。constructor是可选的。
js
import { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<div>
</div>
);
}
}
export default App;
render函数的返回值
当render被调用时,它会检查this.props和this.state的变化并返回以下类型之一:
1.React元素,通过jsx创建的
-
数组或fragments
-
Portals,将子节点渲染到不同的dom中
-
字符串或数值类型,它们在dom中会被渲染成文本节点
-
布尔类型或null 什么都不渲染
函数组件的返回值类型也跟类组件的一样
生命周期
js
class App extends Component {
constructor() {
super();
this.state = {};
//初始化state
}
componentDidMount() {
//组件已经渲染到dom中
}
componentDidUpdate(proProps,preState,snapshot) {
//dom发生更新 ,snapshot getSnapshotBeforeUpdate传递的值
}
componentDidMount() {
// 组件卸载,
}
shouldComponentUpdate(){
return true //是否更新,返回false就不会更新
}
getSnapshotBeforeUpdate(){
//在更新前进行一些操作,返回的数据可以在 componentDidUpdate中获取
return {
name:"aaa"
}
}
change(){
this.setState({
}) //调用setState后会触发render,然后重新渲染,在执行componentDidUpdate
}
render() {
return <div>222</div>;
}
}
组件间的通信
父组件向子组件传参
js
// 父组件
<div>
<Son name={"sssxasa"} age={18}></Son>
</div>
------------------------
//子组件
class Son extends Component {
constructor(props) { // constructor 这一步可以省略
super(props);
}
render() {
const { name, age } = this.props;
return (
<div>
<div>
{name}:{age}
</div>
</div>
);
}
}
propTypes 参数类型
js
import { Component } from "react";
import PropTypes from "prop-types";
class Son extends Component {
render() {
const { name, age } = this.props;
return (
<div>
<div>
{name}:{age}
</div>
</div>
);
}
}
Son.propTypes = {
name: PropTypes.string,
age: PropTypes.number,
};
//设置默认值
Son.defaultProps = {
name: "default",
age: 18,
};
子组件向父组件传值
父组件向子组件传递一个方法,这个方法接受参数,子组件使用时把参数传递过来。
父组件
js
getSon(val) {
console.log(val)
}
render() {
return (
<div>
<Son getSon={(val) => this.getSon(val)}></Son>
</div>
);
}
子组件
js
class Son extends Component {
render() {
const { name, age, getSon } = this.props;
return (
<div>
<div>
{name}:{age}
</div>
<button onClick={() => getSon("传递的值")}>传递值</button>
</div>
);
}
}
react中的插槽
react中有两种方式实现插槽:
组件的children 和props传递react元素
组件的children
这些元素会放到组件实例上,有多个元素时children是一个数组,
只有一个元素时,children就是对应的元素
js
const { children } = this.props;
<div>
<div>{children}</div>
</div>
//通过设置chilidren可以限制传入单个元素或多个元素
Son.propTypes={
children:PropTypes.array //:PropTypes.element
}
props传递react元素
可以通过传递一个函数,由子组件决定渲染的内容
context
React.createContext 创建 需要共享的Context对象
js
import React from "react";
const myContext = React.createContext();
export default myContext;
Context.Provider,每个context对象都会返回一个Provider React组件,它允许组件订阅context的变化。
Provider可以接受一个value,传递给组件
js
render() {
return (
<div>
<myContext.Provider value={{ color: "red", name: "sss" }}>
<Son></Son>
</myContext.Provider>
</div>
);
}
Class.context.Type 挂载在class的contextType 属性会被重新赋值为由React.createContext()创建的Context对象,通过this.context可以使用Context上的值。
js
import { Component } from "react";
import myContext from "./context";
class Son extends Component {
render() {
const { name } = this.context;
return <div>{name}</div>;
}
}
Son.contextType = myContext;
export default Son;
函数式组件使用context需要使用context.Consumer
js
return (
<div>
<myContext.Provider value={{ color: "red", name: "sss" }}>
<Son></Son>
<Test></Test>
</myContext.Provider>
</div>
);
----------------------------------------
import myContext from "./context";
export function Test() {
return (
<div>
<myContext.Consumer>
{(value) => {
return <h1>{value.name}</h1>;
}}
</myContext.Consumer>
</div>
);
}
使用多个provider
createContext可以设置默认值
js
import React from "react";
const myContext = React.createContext();
export default myContext;
export const testContext = React.createContext({
age: 18,
address: "asdasf",
});
js
return (
<div>
<testContext.Provider value={{ age: 18, address: "fwefes" }}>
<myContext.Provider value={{ color: "red", name: "sss" }}>
<Son></Son>
<Test></Test>
</myContext.Provider>
</testContext.Provider>
</div>
);
有多个context时,可以使用Consumer使用对应的context
js
import { Component } from "react";
import myContext, { testContext } from "./context";
class Son extends Component {
render() {
const { name } = this.context;
return (
<div>
{name}
<testContext.Consumer>
{(value) => {
return <h1>{value.address}</h1>;
}}
</testContext.Consumer>
</div>
);
}
}
Son.contextType = myContext;
export default Son;