React第二篇class类组件
Alex
简介:React是facebook(现在叫Meta)出的针对视图层的library库,目前最新版本18X
React官网- 点我去官网
通过这篇文章你会学到以下知识:
- 你将会学习到
- 如何创建和嵌套组件
- 如何添加标签和样式
- 如何显示数据
- 如何渲染条件和列表
- 如何对事件做出响应并更新界面
- 如何在组件间共享数据
1、首先我们在HML中使用react
我们需要准备三个东西
babel 作用是代码解析何jsx编译
react 核心库
react-dom 是在浏览器种使用react的必备插件
上面的第三方库 可以到NPM去下载(注意版本)
NPM-点我去NPM官网
2、 class类组件定义
class定义的组件,又叫类组件,这种组件可有自己的局部状态和生命周期
class定义的组件都需要继承自Component或者PereComponent(相当于function定义的组件中为组件添加一个memo缓存效果)
每一个class定义的组件都需要一个render方法,这个方法返回当前组件的html内容
在class定义的组件中,如果改变state数据,需要调用setState方法
setState是异步的,其实它可以接收两个参数
参数一 表示要改变的数据
参数二 表示数据改变之后的回调函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>class定义组件</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
// 两种方式定义的组件是可以嵌套使用的
class Counter extends React.Component {
constructor(props) {
super(props);
// 可以通过state属性为组件定义状态数据
this.state = {
count: 1,
name: "这是一个计数器",
};
}
render() {
// 每一次数据或者属性改变的时候这个方法会重新执行
// console.log("render方法执行了");
return (
<>
<h1>这是一个组件---{this.state.name}</h1>
<h2>count值为:{this.state.count}</h2>
<button
onClick={() => {
this.setState(
{
count: this.state.count + 1,
},
function () {
console.log(this.state.count);
}
);
// console.log(this.state.count);
}}
>
+1
</button>
</>
);
}
}
const App = () => {
return (
<>
<Counter />
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
3、 this指向问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传参</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { Component } = React;
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 1,
};
// 在class定义的组件中绑定this的时候,建议使用这种方案
// this.clickHandle3 = this.clickHandle3.bind(this);
}
clickHandle() {
console.log(this);
}
clickHandle2() {
console.log(this);
}
clickHandle3() {
console.log(this);
}
render() {
return (
<>
<h1>当前的计数值为:{this.state.count}</h1>
<button
onClick={() => {
console.log(this);
}}
>
改变
</button>
<button onClick={this.clickHandle.bind(this)}>改变2</button>
<button onClick={() => this.clickHandle2()}>改变3</button>
<button onClick={this.clickHandle3}>改变4</button>
</>
);
}
}
const App = () => {
return (
<>
<Counter></Counter>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
4、 class类组件的组件传参(与function组件传参一样)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传参</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const context = React.createContext(); // 创建
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 1 };
}
render() {
console.log(this.context);
return (
<>
<h1>计数器的值为:{this.state.count}</h1>
<h3>父组件传过来的步长为:{this.props.step}</h3>
<p>全局context中的数据为:{this.context.name}</p>
<button
onClick={() => {
this.props.showNum("998");
}}
>
改变
</button>
</>
);
}
}
Counter.contextType = context; // 只需要为组件设置contextType属性
const App = () => {
const [step, gaiBianStep] = React.useState(1);
const showNum = (num) => {
alert(num);
};
return (
<>
<input
type="range"
min="1"
max="10"
step="1"
defaultValue={step}
onChange={(e) => {
gaiBianStep(e.currentTarget.value * 1);
}}
/>
<Counter step={step} showNum={showNum} />
</>
);
};
ReactDOM.render(
<context.Provider value={{ name: "我是数据" }}>
<App />
</context.Provider>,
document.querySelector("#app")
);
</script>
</body>
</html>
5、PureComponent(缓存一个组件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PureComponent</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
// 在项目中建议使用PureComponent实现组件的继承
class Item extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
console.log("组件渲染了");
return (
<>
<h2>{this.props.name}</h2>
</>
);
}
}
const App = () => {
const [list, setList] = React.useState([]);
return (
<>
<input
type="text"
placeholder="请输入内容"
onKeyUp={(e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
setList([
...list,
{ id: Date.now(), name: e.currentTarget.value },
]);
}
}}
/>
<hr />
{list.map((item) => (
<Item key={item.id} {...item} />
))}
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
6、组件的生命周期
- constructor----构造器
- componentWillMount —将要挂载
- componentDidMount —挂在完成
- componentWillReceiveProps — 将要接受新的属性
- shouldComponentUpdate 是否允许更新
- componentWillUpdate— 将要更新
- componentDidUpdate —更新完成
- componentWillUnmount —销毁
- render—渲染
当页面初次渲染是执行顺序:
- constructor----构造器
- componentWillMount —将要挂载
- render—渲染
- componentDidMount —挂在完成
当页面更新的是执行顺序:
第一种情况
- shouldComponentUpdate 是否允许更新 (返回 true -----是)
- componentWillUpdate— 将要更新
- render—渲染
- componentDidUpdate —更新完成
第二种情况
- shouldComponentUpdate 是否允许更新 (返回false -----否)
页面不会在更新
组件之间进行嵌套的时候生命周期钩子函数的执行顺序:
- 父组件-constructor----构造器
- 父组件-componentWillMount —将要挂载
- 父组件-render—渲染
- 子组件-constructor----构造器
- 子组件-componentWillMount —将要挂载
- 子组件- render—渲染
- 子组件 componentDidUpdate —更新完成
- 父组件componentDidUpdate —更新完成
- 总结:先执行父组件的构造器,将要挂载,执行到render的时候,开始解析子组件的生命周期钩子函数,当所有的子组件都挂载完成,在执行父组件的挂载完成
两个注意点:
一、属性或者数据改变的时候render会重新执行, 在render中不能改变数据,会引起死循环
二、 非常重要,主要用来做组件性能优化,
那些不需要在页面中展示的数据改变的时候可以返回false
返回false的时候后续的更新阶段不会再执行
返回true那么后续的更新阶段就会执行
这个方法接收两个参数(下一次的属性, 下一次的状态)
shouldComponentUpdate
(nextProps, nextState) {
console.log(“shouldComponentUpdate”);
console.log(nextProps);
console.log(nextState);
return false;
}
7、refs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>refs</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
class App extends React.Component {
componentDidMount() {
console.log((this.refs.ppp.style.color = "red"));
}
render() {
return (
<>
<h1>这是一个组件</h1>
<p ref="ppp">我是一段很长的文字</p>
</>
);
}
}
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
8、练习todolist
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>todo-list</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { PureComponent } = React;
class TodoInput extends PureComponent {
constructor(props) {
super(props);
this.saveHandle = this.saveHandle.bind(this);
}
saveHandle(e) {
if (e.keyCode === 13 && e.currentTarget.value) {
this.props.save(e.currentTarget.value);
e.currentTarget.value = "";
}
}
render() {
return <input placeholder="请输入内容" onKeyUp={this.saveHandle} />;
}
}
class Todo extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<>
<h3>{this.props.content}</h3>
{this.props.isEnd ? null : (
<button
onClick={() => {
this.props.end(this.props.id);
}}
>
完成
</button>
)}
<button>删除</button>
<hr />
</>
);
}
}
class Todos extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<>
{this.props.list.map((item) => (
<Todo key={item.id} {...item} end={this.props.end} />
))}
</>
);
}
}
class TodoList extends PureComponent {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.save = this.save.bind(this);
this.end = this.end.bind(this);
}
save(txt) {
this.setState({
list: [
...this.state.list,
{ id: Date.now(), content: txt, isEnd: false },
],
});
}
end(id) {
this.setState({
list: this.state.list.map((item) =>
item.id == id ? { ...item, isEnd: true } : { ...item }
),
});
}
render() {
return (
<>
<TodoInput save={this.save} />
<hr />
<Todos list={this.state.list} end={this.end} />
</>
);
}
}
const App = () => {
return (
<>
<TodoList />
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>