第一节、理解react和react-dom两个库
1、react的api是很少的,学一次就不用了,基本就是js功力。
2、react设计之初就是用jsx来描述UI,所以解耦了dom操作。
react 做逻辑层。
react-dom 做渲染层,操作虚拟dom,挂载页面。
3、移动端、可以使用别的渲染库来做。
第二节、剖析JSX的实质
1、jsx语法即 js 和 html 的混合体,实际的核心逻辑是用js实现的。
2、常见的代码如下
ReactDOM.render(<App/>,document.getElementById('root'));
3、jsx的实质就是React.createElement的 反复调用。
4、我们react里面的通常写法:
class HelloLxq extends React.Component{
render(){
return(
<div>
Hello {this.props.name}
</div>
);
}
}
ReactDOM.render(
<HelloLxq name="lxq"/>,
document.getElementById('hello-lxq')
)
5、实际上JSX的写法
class HelloLxq extends React.Component{
render(){
return React.createElement(
'div',
null,
'Hello',
this.props.name
);
}
}
ReactDOM.render(
React.createElement(
HelloLxq,
{name:'lxq'}
),
document.getElementById('hello-lxq')
);
第三节、state & setState == 渲染 & 更新
1、在组件里面我们用 {} 在 jsx里面渲染变量值。
2、如果数据需要修改,并且需要页面同时响应变化,那就需要把变量放在state里面,同时使用 steState修改。
3、初始化状态
// 初始化状态
this.state = {
count:0
}
4、更新状态使用 steState, 不能直接 this.state.count = xxx
// 更新状态
this.setState({
count: this.state.count + 1
})
5、注意事项:
5.1、setState 是异步的,底层设计(性能优化)同一个生命周期会批量操作更新 state
5.2、setState第二个参数可选,是一个回调函数,可以拿到最新的state
5.3、setState第一个参数可以是一个function, 需要返回{}。函数的params: prevState、prevProps。用来
处理修改state时需要依赖上一次的state值。如下:
this.setState((prevState,prevProps)=>({
count:prevState.count+1
}),() => {
// 这里可以获取到最新的state
console.log(this.state.count);
})
6、手敲一遍
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
msg1: '您好呀,我是state里面的msg1',
count: 0,
}
}
// 这里的写法和 constructor 里面的 this.state = {} 是一样的
// state = {
// msg1:'您好呀,我是state里面的msg1'
// }
componentDidMount() {
// this.setState({
// count: this.state.count + 1
// }, () => {
// console.log(this.state.count,'这里是后输出,update后的最新值');
// })
// console.log(this.state.count,'这里是先输出');
// 如果修改的 state 是依赖上一次的 state 可以这么写
// this.setState((prevState, prevProps)=>{
// return {
// count: prevState.count+1
// }
// })
// 上面代码的简略写法
this.setState((prevState, prevProps) => ({
count: prevState.count + 1
}), () => {
console.log(this.state.count, '这里是后输出,update后的最新值');
})
console.log(this.state.count, '这里是先输出');
}
render() {
const msg = "大家好,我是lxq";
return (
<div>
<p>欢迎学习react!</p>
<p>{msg}</p>
<h1>{this.state.msg1}</h1>
<h2>{this.state.count}</h2>
</div>
)
}
}
第四节、props 基础使用
1、父组件向子组件传递属性利用props接收
2、使用例子如下:
// 父组件传入
<PropsDemo title="hello world!"></PropsDemo>
// 子组件接收
// class组件使用
<h1>{this.props.title}</h1>
// 函数型组件使用
function xxx (props){
return (
<h1>{props.title}</h1>
)
}
3、手敲一遍
App.js
import PropsDemo from './child/PropsDemo'
...
render() {
return (
<div>
...
<PropsDemo title="hello world!"></PropsDemo>
</div>
)
}
PropsDemo.js
// class 组件
// import React, { Component } from 'react'
// export default class PropsDeom extends Component {
// render() {
// return (
// <div>
// {this.props.title}
// </div>
// )
// }
// }
// 函数式组件
import React from 'react'
// export default function PropsDemo(props) {
// return (
// <div>
// {props.title}
// </div>
// )
// }
// 参数解构
export default function PropsDemo({ title }) {
return (
<div>
{title}
</div>
)
}
第五节、条件渲染 & 数据循环
1、条件渲染写法、一般使用三目表达式
// 1.三目表达式写法
{this.state.show?<h2>{this.props.titel}</h2>:null}
// 2.在render函数里面使用变量装载结果
let result = this.state.show?<h1>{this.props.title}</h1>:null;
{result}
// 3.直接写if else
let result
if(this.state.show){
result = (<h1>{this.props.title}</h1>)
}else{
result = null
};
{result}
2、数据循环渲染写法
class Loop extends React.Component{
constructor(props){
super(props);
this.state = {
goods:[
{title:'webpack教程',price:19.8},
{title:'vue教程',price:29.8},
{title:'react教程',price:39.8},
{title:'node教程',price:49.8},
]
}
}
render(){
return <div>
<ul>
{this.state.goods.map(item=>{
return <li key={item.title}>
<span>{item.title}</span>
<span>¥{item.price}</span>
</li>
})}
</ul>
</div>
}
}
3、手敲一遍
Condition.js
import React, { Component } from 'react'
export default class Condition extends Component {
constructor(props){
super(props);
this.state = {
showTitle:true
}
setTimeout(() => {
this.setState({
showTitle:false
})
}, 3000);
}
render() {
// 第2种写法
// let result = this.state.showTitle?<p>{this.props.title}</p>:null;
// 第3种写法
let result
if(this.state.showTitle){
result = <p>{this.props.title}</p>;
}else{
result = null;
}
return (
<div>
<h3>数据条件渲染展示</h3>
{/* 第1种写法 */}
{/* {this.state.showTitle?<p>{this.props.title}</p>:null} */}
{/* 第2种写法 */}
{result}
</div>
)
}
}
Loop.js
import React, { Component } from 'react'
export default class Loop extends Component {
constructor(props) {
super(props);
this.state = {
goods: [
{ title: 'webpack教程', price: 19.8 },
{ title: 'vue教程', price: 29.8 },
{ title: 'react教程', price: 39.8 },
{ title: 'node教程', price: 49.8 },
]
}
}
render() {
return <div>
<h3>{this.props.title}</h3>
<ul>
{this.state.goods.map(item=>(
<li key={item.title}>
<span>{item.title}</span>
<span>¥{item.price}</span>
</li>
))}
</ul>
</div>
}
}
第六节、事件
1、点击事件为例,使用方法如下
// 小驼峰,事件名称用{}包裹
<button onClick={xxx}></button>
2、由于React的 this 指向问题,事件绑定有四种写法:
2.1、利用bind绑定,这种写法很少少用 。点击传参- no
// 在constructor里面利用bing绑定this,解决方法this的指向问题
constructor(props){
super(props)
this.switchShowTitle = this.switchShowTitle.bind(this);
}
switchShowTitle() {
this.setState()
}
<button onClick={this.switchShowTitle}>切换显示</button>
2.2 利用bind绑定,这种写法很少用 。点击传参-使用bind
// 在constructor不绑定this的指向
constructor(props){
super(props)
}
switchShowTitle(param) {
console.log(param);
this.setState()
}
<button onClick={this.switchShowTitle.bind(this,'点击参数')}>切换显示</button>
2.3 利用 = 号赋值,加上箭头函数,这种写法常用 。点击传参-使用bind
// 在constructor不绑定this的指向
constructor(props){
super(props)
}
switchShowTitle = (param)=>{
console.log(param);
this.setState()
}
<button onClick={this.switchShowTitle}>切换显示</button>
2.4 事件上直接使用箭头函数调用, 这种写法常用。点击传-正常
// 在constructor不绑定this的指向
constructor(props){
super(props)
}
switchShowTitle(param) {
console.log(param);
this.setState()
}
<button onClick={() => this.switchShowTitle('点击参数')}>切换显示</button>
3、手敲一遍
EventFn.js
import React, { Component } from 'react'
export default class EventFn extends Component {
constructor(props) {
super(props);
// 第1种
// this.switchShowTitle = this.switchShowTitle.bind(this);
this.state = {
showTitle: true
}
}
// 第1、2、4种
switchShowTitle(param) {
console.log(param);
this.setState((prevState, prevProps) => ({
showTitle: !prevState.showTitle
}))
}
// 第3种
// switchShowTitle = (param) => {
// console.log(param);
// this.setState((prevState, prevProps) => ({
// showTitle: !prevState.showTitle
// }))
// }
render() {
return (
<div>
{this.state.showTitle ? <h3>{this.props.title}</h3> : null}
{/* 第1种 */}
{/* <button onClick={this.switchShowTitle}>切换显示</button> */}
{/* 第2种 */}
{/* <button onClick={this.switchShowTitle.bind(this,'点击')}>切换显示</button> */}
{/* 第3种 */}
{/* <button onClick={this.switchShowTitle}>切换显示</button> */}
{/* 第4种 */}
<button onClick={() => this.switchShowTitle('点击参数')}>切换显示</button>
</div>
)
}
}
第七节、样式编写
1、行内样式编写
<img style={{width:"100px", height:"100px"}} />
2、添加class 类名、属性
<img className="border-1px" />
<img className={className} alt={title}/>
第八节、实现双向数据绑定
1、React实现input的双向数据绑定要点
1.1、动态绑定value属性
1.2、监听input的onChage事件
2、手敲一遍
TwoWayDataBind.js
import React, { Component } from 'react'
export default class TwoWayDataBind extends Component {
constructor(props) {
super(props)
this.state = {
inputVal: 'default-value'
}
}
// 绑定input的change事件
// 函数1可行
// inputOnChange(e) {
// this.setState({
// inputVal: e.target.value
// })
// }
// 函数2可行
inputOnChange = (e) => {
this.setState({
inputVal: e.target.value
})
}
render() {
return (
<div>
<h3>{this.props.title}</h3>
<input type="text" value={this.state.inputVal} onChange={e => this.inputOnChange(e)} />
<p>{this.state.inputVal}</p>
</div>
)
}
}
第九节、生命周期 基础使用
1、示意图
2、生命周期钩子
// 组件构建
constructor(props) {}
// 组件将要挂载
componentWillMount() {console.log('我们会 获取数据,操作方法')}
// 组件render渲染
render(){}
// 组件已经挂载
componentDidMount() {console.log('我们会 操作dom')}
// 接收父组件传递的属性有变化, 作相应的响应
componentWillReceiveProps() {console.log('我们会 处理异步得到的数据')}
// 组件是否需要更新,返回布尔值,优化点
shouldComponentUpdate(nextProps, nextState) {
// 使用该方法让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,
// 而且该方法并不会在初始化渲染或当使用forceUpdate()时被调用,我们要做的只是这样:
return nextState.someData !== this.state.someData
// 但是,state里的数据这么多,还有对象,还有复杂类型数据,react的理念就是拆分拆分再拆分,这么多子组件,我要每个组件都去自己一个一个对比吗??
// 不存在的,这么麻烦,要知道我们的终极目标是不劳而获-_-
// React.PureComponent 可以看一下
}
// 组件将要更新
componentWillUpdate() {}
// 组件已经更新
componentDidUpdate() {}
// 组件将要销毁
componentWillUnmount() {console.log('我们会 清除计时器')}
3、手敲一遍
LifeCycle.js
import React, { Component } from 'react'
class LifeCycleSon extends Component {
constructor(props) {
console.log('0.生命周期-组件正在构建');
super(props)
this.state = {
title: '子组件内容'
}
}
// componentWillMount rename UNSAFE_componentWillMount
componentWillMount() {
// 可以进行API的调用,数据获取,不能dom操作
console.log('1.生命周期-组件将要挂载');
}
componentDidMount() {
// 可以进行dom操作,对我们的状态进行更新操作
console.log('3.生命周期-组件已经挂载');
}
componentWillReceiveProps() {
console.log('4.生命周期-组件获取父级属性更新');
}
shouldComponentUpdate() {
console.log('5.生命周期-组件是否需要更新,需要返回Boolean值')
return true
}
componentWillUpdate() {
console.log('6.生命周期-组件将要更新');
}
componentDidUpdate() {
console.log('7.生命周期-组件已经更新');
}
componentWillUnmount() {
console.log('8.生命周期-组件将要销毁');
}
render() {
console.log('2.生命周期-组件render');
return (
<div>
<p>{this.state.title}</p>
<p>{this.props.context}</p>
</div>
)
}
}
export default class LifeCycle extends Component {
constructor(props) {
super(props)
this.state = {
sonText: '父级传值-默认值',
isShowSon: true,
}
setTimeout(() => {
this.setState({
sonText: (<b>父级传值-改变了</b>),
})
}, 2000);
setTimeout(() => {
this.setState({
isShowSon: false,
})
}, 4000);
}
render() {
return (
<div>
<h3>组件生命周期演示</h3>
{this.state.isShowSon ? <LifeCycleSon context={this.state.sonText}></LifeCycleSon> : '子组件已销毁'}
</div>
)
}
}
基本使用总结完了,系统讲解了一下常用方式,后面提升内容还在持续更新!💻