29.9React课程
第1节:react核心
(react核心&)
react核心&
如果是cdn最好增加crossorgin跨域属性,直接避开校验直接引入资源文件
crossorigin跨域引入CDN,create-react-app,npm run eject
快速搭建react脚手架
构建npm run build 生产构建,CIA工具配置通过eject打碎项目可以看到webpack的配置,执行就不可逆。
(初识Jsx&)
初识Jsx&
jsx语法,{}
函数也是表达式
把变量与函数可以直接插入jsx语法中,react.render进行数据渲染
把jsx挂在到root 的html中
(条件渲染&)
条件渲染&
要在jsx以外做判断
逻辑与&&,条件语句不能再表达式里使用
列表渲染
具有唯一标识性的做为key
显示图片
不能使用相对路径./logo.png,打包路径不同
动态渲染日期Date(),jsx的条件渲染表达式,arr,map,src与style样式图片引入,className,css模块化
import React from "react"; //=>vdom
import ReactDOM from "react-dom";
import pic from "./logo.png";
import classNames from "classnames";
import TestClass from "./TestClass";
import TestHandle from "./TestHandle";
//引入css模块
import "./index.css";
//引入模块化css 需要名称
import StyleCss from "./index.module.css";
//jsx
//使用表达式 {} 里面 只要是合法的表达式 都可以
// const name = "react";
// const user = {
// firtName: "han",
// lastName: "lao"
// };
// function joinName(user) {
// return user.firtName + "-" + user.lastName;
// }
// const tags = <span>hello span</span>;
// const jsx = <p>我喜欢{tags}</p>; //原生dom元素 =》React 元素
// React.createElement(<p>我是p标签</p>)
//动态渲染
// function tick() {
// const ele = <div>{new Date().toLocaleTimeString()}</div>;
//
// }
// tick();
// setInterval(tick, 1000);
const isShow = true;
// let jsx;
// if (isShow) {
// jsx = <p>我喜欢1</p>;
// } else {
// jsx = <p>我喜欢2</p>;
// }
//条件语句 不能在{}里使用
// if
// 三元运算
// 逻辑与
const jsx = isShow && <p>我喜欢1</p>;
const arr = [1, 2, 3, 4];
const lis = arr.map((item, index) => <li key={index}>{item}</li>);
// ReactDOM.render(<ul>{lis}</ul>, document.getElementById("root"));
//css-in-js
// const styles = {
// border: "1px red solid",
// height: 200
// };
//为什么要使用className,目的是避开关键字
// /* <label htmlfor=""></label> */
// function Lis(props){
// }
//首字母必须要大写
function Welcome(props) {
console.log(props);
//遵守单向数据流原则,不要对props进行修改
// return [<div>我是div1</div>, <div>我是div2</div>];
// 解决列表渲染
return (
// <React.Fragment>
// <div>1</div>
// <div>2</div>
// </React.Fragment>
<ul>{lis}</ul>
);
}
//使用数组
//dom元素属性
{
/* <img
src={pic}
alt="图片"
className={classNames("border1", { height2: true })}
/> */
}
ReactDOM.render(
<TestHandle name={"React Comp"} />,
document.getElementById("root")
);
index.css
.border1 {
border: 1px blue solid;
}
.height2 {
height: 200px;
}
设置元素样式,替换内部元素样式
引入css样式
定义样式,className引入外面class模块类名
.border1 {
border: 1px blue solid;
}
.height2 {
height: 200px;
}
模块化的css
index.module.css
.border1 {
border: 1px blue solid;
}
.height2 {
height: 200px;
}
样式解决方案 styled-components,styled-jsx,classnames
(组件&)
组件&
函数式组件与类组件
函数组件与props
import React from "react"; //=>vdom
import ReactDOM from "react-dom";
import pic from "./logo.png";
import classNames from "classnames";
import TestClass from "./TestClass";
import TestHandle from "./TestHandle";
//引入css模块
import "./index.css";
//引入模块化css 需要名称
import StyleCss from "./index.module.css";
//jsx
//使用表达式 {} 里面 只要是合法的表达式 都可以
// const name = "react";
// const user = {
// firtName: "han",
// lastName: "lao"
// };
// function joinName(user) {
// return user.firtName + "-" + user.lastName;
// }
// const tags = <span>hello span</span>;
// const jsx = <p>我喜欢{tags}</p>; //原生dom元素 =》React 元素
// React.createElement(<p>我是p标签</p>)
//动态渲染
// function tick() {
// const ele = <div>{new Date().toLocaleTimeString()}</div>;
//
// }
// tick();
// setInterval(tick, 1000);
const isShow = true;
// let jsx;
// if (isShow) {
// jsx = <p>我喜欢1</p>;
// } else {
// jsx = <p>我喜欢2</p>;
// }
//条件语句 不能在{}里使用
// if
// 三元运算
// 逻辑与
const jsx = isShow && <p>我喜欢1</p>;
const arr = [1, 2, 3, 4];
const lis = arr.map((item, index) => <li key={index}>{item}</li>);
// ReactDOM.render(<ul>{lis}</ul>, document.getElementById("root"));
//css-in-js
// const styles = {
// border: "1px red solid",
// height: 200
// };
//为什么要使用className,目的是避开关键字
// /* <label htmlfor=""></label> */
// function Lis(props){
// }
//首字母必须要大写
function Welcome(props) {
console.log(props);
//遵守单向数据流原则,不要对props进行修改
// return [<div>我是div1</div>, <div>我是div2</div>];
// 解决列表渲染
return (
// <React.Fragment>
// <div>1</div>
// <div>2</div>
// </React.Fragment>
<ul>{lis}</ul>
);
}
//使用数组
//dom元素属性
{
/* <img
src={pic}
alt="图片"
className={classNames("border1", { height2: true })}
/> */
}
ReactDOM.render(
<TestHandle name={"React Comp"} />,
document.getElementById("root")
);
TestClass.js 类组件,constructor ,componentDidMount,setState异步
import React, { Component } from "react";
class TestClass extends Component {
constructor(props) {
super(); //disbled
// this.state = {
// date: new Date()
// };
this.state = {
counter: 0
};
// this.state.counter = 1;
//setState()
}
// state = {
// date: new Date()
// };
//生命周期函数 已挂载
componentDidMount() {
// this.timerId = setInterval(() => {
// this.setState({
// date: new Date()
// });
// }, 1000);
// this.setState({
// counter: this.state.counter + 1
// });
// this.setState({
// counter: this.state.counter + 1
// });
// this.setState({
// counter: this.state.counter + 1
// });
//完全取决于是否需要最新的值
this.setState((state, props) => ({ counter: state.counter + 1 }));
this.setState((state, props) => ({ counter: state.counter + 1 }));
this.setState((state, props) => ({ counter: state.counter + 1 }));
// setTimeout(() => {
// console.log(this.state.counter);
// }, 0);
document.body.addEventListener("click", this.changeValue, false);
// console.log(this.state.counter); //1 ==== 0
}
componentWillUnmount() {
// clearInterval(this.timerId);
}
changeValue = () => {
this.setState({ counter: this.state.counter + 1 });
console.log(this.state.counter);
};
render() {
// return <div>{this.state.date.toLocaleTimeString()}</div>;
return <div>{this.state.counter}</div>; //3
}
}
export default TestClass;
s
props在的调用得到时候传入,接收父组件传递的属性并展示,props名字可以修改作为形参。
组件首字母必须要大写,大写当做组件处理,小写当做原生Dom来处理。
可以传递字符串与{}形式的 字符串,也可以传递数组和对象,所有属性函数式组件都是通过props接收的
遵守单向数据流,接收到属性不建议对属性进行修改
组件的使用呢当做一个标签来使用,首字母要大写区分原生Dom
渲染过程
return的元素只能有一个根节点,需要一个包裹元素<div>
返回兄弟级的div元素
Fragment包裹兄弟元素,可以使用短标签
使用Fragment需要有key
class组件,拥有状态与生命周期,继承component
导出直接引入组件名即可
return直接返回null不会进行任何渲染
(组件状态管理&)
组件状态管理&
数据发生变化影响页面内容,需要维护state,props在父组件指定一经指定不再改变,遵守单一数据流。
状态改变,组件重新调用render方法,更新UI。
constructor接收属性
可变的属性通过state来管理状态,不要对state直接修改,通过setState来设置
生命周期钩子,componentDidMount 当Dom已经挂在到HTML里面,钩子会自动执行,在钩子函数中增加定时器修改state来重新执行渲染render函数。
通过key来重新设置state
组件销毁的时候还要清除定时器
在类组件可以省略constructor,state通过成员变量来定义,this指向组件实例
最终输出0因为setState是异步的
state的更新会被合并,组件多次state同一个可以最终合并为一个,只有最后一个执行了,输出1
拿到最新的值,需要接受一个函数实现
获取最新state值三种方式
异步变为同步,最终结果为3
获取最新值,定时器0立即执行为3,使用原生世界
箭头函数修改this指向,setState修改state
TestClass.js
import React, { Component } from "react";
class TestClass extends Component {
constructor(props) {
super(); //disbled
// this.state = {
// date: new Date()
// };
this.state = {
counter: 0
};
// this.state.counter = 1;
//setState()
}
// state = {
// date: new Date()
// };
//生命周期函数 已挂载
componentDidMount() {
// this.timerId = setInterval(() => {
// this.setState({
// date: new Date()
// });
// }, 1000);
// this.setState({
// counter: this.state.counter + 1
// });
// this.setState({
// counter: this.state.counter + 1
// });
// this.setState({
// counter: this.state.counter + 1
// });
//完全取决于是否需要最新的值
this.setState((state, props) => ({ counter: state.counter + 1 }));
this.setState((state, props) => ({ counter: state.counter + 1 }));
this.setState((state, props) => ({ counter: state.counter + 1 }));
// setTimeout(() => {
// console.log(this.state.counter);
// }, 0);
document.body.addEventListener("click", this.changeValue, false);
// console.log(this.state.counter); //1 ==== 0
}
componentWillUnmount() {
// clearInterval(this.timerId);
}
changeValue = () => {
this.setState({ counter: this.state.counter + 1 });
console.log(this.state.counter);
};
render() {
// return <div>{this.state.date.toLocaleTimeString()}</div>;
return <div>{this.state.counter}</div>; //3
}
}
export default TestClass;
(事件处理&)
事件处理&
事件注意this指向问题
根据用户输入的值来展示最新的值,要更新name,获取用户输入的值,找不到this与e
箭头函数传递this,箭头函数中传递参数
通过handler绑定this,直接调用箭头函数就可以
通过bind绑定this
官方建议在构造函数中bind(this)
(组件通信&)
组件通信&
单向数据流,在子组件的事件中传入值,父组件就能接收到值了。
子组件修改父组件里面的东西。
this.props.change接收父组件传递而来的事件
解决this出现问题,传递test执行当前组件的handler函数
this传递出现异常,通过箭头函数传递
点击没有执行事件
点击div执行handle事件
传递的是test要执行test不能执行handle
处理handle()方法this的指向,子组件更改父组件属性,用到事件就要考虑this指向问题
onChange事件,onClick事件,绑定this的三种方式,状态提升
import React from "react";
class TestHandle extends React.Component {
constructor(props) {
super();
this.state = {
name: "",
counter: 0,
age: 18
};
// this.handleTest = this.handleTest.bind(this,e);
}
handleTest = () => {
//如何在函数内部正确使用this
this.setState({
age: this.state.age + 1
});
};
// handleTest2() {
// //如何在函数内部正确使用this
// this.setState({
// age: this.state.age + 1
// });
// }
// handleTest3() {
// //如何在函数内部正确使用this
// this.setState({
// age: this.state.age + 1
// });
// }
handleChange(e) {
this.setState({
name: e.target.value
});
}
handle() {
this.setState({
counter: this.state.counter + 1
});
}
render() {
//bind
//箭头函数
return (
<div
onClick={e => {
this.handleTest(e);
}}
>
<Msg
test={() => {
this.handle();
}}
counter={this.state.counter}
/>
{/* <input type="text" value={this.state.name} />
<p>{this.state.age}</p> */}
</div>
);
}
}
const Msg = props => {
return (
<div
onClick={() => {
props.test();
}}
>
{props.counter}
</div>
);
};
export default TestHandle;
(生命周期&)
生命周期&
component生命周期
componentDidMount()已经挂载函数
state改变通过shouldComponentUpdate进行比对更新,return true往下执行
Initialization初始化props和state,之后Mounting挂载,之后Updation更新阶段,