1.React (基础篇)
React介绍:
专门构建于用户界面的js库(顶多它是mvc中的v层框架)
核心思想,通过数据操作视图。
官方(推荐使用)脚手架:create-react-app
中文网:https://react.docschina.org/
难点:英文、webpack
背景:react 是 Facebook 出品,背景大、生态比较丰富(pc、安卓、ios都适用)
相对vue来说只是写法不一样,思想都类似的,代码相对vue来说要多一点点。基本上都是原生,自己写的功能多一些。
组件声明方式:
react通过声明一个类(函数)来创建UI的
1. class Person extends React.Component{} (类的申明方式有:状态、this、生命周期。hooks 出现之前,推荐用这种方式申明。)
2. function Child(props, ref) {} (hooks 出现之后,函数式组件也是必须要会的,比类组件更新。)
搭建 react 项目
初学推荐使用脚手架: create-react-app
npx create-react-app my-app (my-app 自己起的文件名)
cd my-app
npm start / yarn start
React 全家桶:
react 、 react-router-dom 、 redux(mobx) 、 第三方UI库antd 、 react-native(移动应用) 、 开发原生APP
react:(学习的内容)
jsx语法
state
props
数据的通信
使用:
// 1.引包 react 、react-dom
import React from 'react'; //主要的库
import ReactDOM from 'react-dom'; //把jsx转成能够让浏览器识别的工具
// 3.热更新:(可用可不用)
if(module.hot){
module.hot.accept();
}
/*
挂在组件。(根节点的挂载)
*** ReactDOM.render()是个方法。三个参数:
第一个参数:
模板、组件
第二个参数:
挂载的根节点
第三个参数:
挂载完成之后触发的回调函数
*/
// 2.ReactDOM.render
ReactDOM.render(
<div>你好,世界!!!!
<input
// defaultValue = {'123'}
value = {'456'}
onChange = {()=>{
}}
/>
</div>,
document.getElementById('root'),
()=>{
console.log('挂载成功')
}
);
jsx
jsx -> javascript + xml 一种js和自定义写法的混合模式
jsx 语法主要是为了更好的读、写模板或者组件。
jsx 语法浏览器是不识别的,通过babel的方式吧jsx转成浏览器识别的代码(babel : www.babeljs.cn)。
在react中,写<div></div>
,其实就等同于写了一个 React.createElement('div',children:[],'click','active')
jsx规则:
1.遇到样式中的 class ,直接变成className
2.标签必须闭合 (/),特别是单标签要注意
3.{}
*1)里面放js代码,可以运行(运算) 比如:{console.log(1+'1')}
*2)默然帮你展开数组
[1,2,3] - > 1 2 3
[<li />,<li />]如果数组中的值为组件(列表),那么一定要给列表中的每一项加key(key:一个唯一的值),为了优化
3)注释 {// 或者 /*2/}
*4)可以申明函数,但不能直接调用
5)value={a} 赋值某个元素的属性
6)设置style={{width:'200px',height:'200px',...}} 花括号包着一个对象
4.表单元素设置默认值(value='xxx')的时候会报错,因为它认为input为一个受限的组件。value值是动态就会操作数据(value就一定会变化),会变化,就一定要有事件(onChange),所以才会报错。
比如:<input value="1"/> 报错
两种方式解决:
1.给表单元素加上事件(onChange)(受控组件,官方推荐使用)
<input
value = {a}
onChange = {()=>{
}}
/>
2.定义默认值的时候就使用 defaultValue (非受控组件)
<input
defaultValue = '123'
/>
5.<img src={require('./images/地址.png')} alt=""/> 用img引入图片的时候,要包{require('地址')}的方式
* 循环数据渲染的时候,引入图片地址会出现无法加载的问题:
解决:
1. src={require(""+地址)},括号中放 地址+空字符串。并且图片要在同级目录下,也就是不能出现 ../
2. 把相同的绝对路径写在 字符串里 --> src={require(" ../相同的路径/xxx "+地址)} 。此时可以出现 ../
6.用 ref 来快速找到DOM元素
1)给元素绑定 ref <div ref = "a" > </div>
2)用 this.refs.a 来获取相对应的元素。
定义组件的方式:(参考课件:2019-01-15_React -> app -> arc -> index3.js )
import React from 'react'; //主要的库
import ReactDOM from 'react-dom'; //把jsx转成能够让浏览器识别的工具
//热更新
if (module.hot) {
module.hot.accept();
}
//组件:申明一个类。***一定要注意:类的首字母要大写(App)。
//组件在挂在的时候,会先执行construction,只会执行一次,然后经过几个钩子函数之后,走到render,
//只要数据发生变化,就再次执行render,而construction 是不会再改变
class App extends React.Component {
constructor(props){
super(props); //super的作用: 1.传参 2.拿this
console.log(props)
}
render(){
//普通的render中的return上面写逻辑,return下面是UI
let {aaa,bbb,ccc} = this.props
return(
<div>
<h1>组件</h1>
<div>{aaa}{bbb}{ccc}</div>
</div>
)
}
}
//组件的申明:可以是个类,还可以是一个函数
function Ppa(){
return(
<div>
<h1>组件2</h1>
</div>
)
}
/*
属性中如果有两个重复的,后面会把前面的覆盖
...[a,b,c]
...{a:'1',b:2,}
*/
ReactDOM.render(
<div>
{/* <App aaa='你好' bbb='世界' ccc={[1,2,3]} /> */}
<App {...{
aaa:'hello',
bbb:'word',
ccc:[4,5,6]
}}/>
<Ppa/>
</div>,
document.getElementById('root'),
);
- 第一种
class App extend React.Component{}
- 第二种
在import React,{Component} from 'react'; 引 Component
class App extend Component{ // 推荐使用 class,类名首字母要大写
render(){
<div>
<h1>组件1</h1>
</div>
}
}
- 第三种
function Ppa(){
return(
<div>
<h1>组件2</h1>
</div>
)
}
写方法的时候,如果不对函数做处理,事件函数中的this指向undefined
解决方案:
1.使用create-app (推荐使用这种)
click = () => {} //把匿名箭头函数赋值给click
2.bind,this
click(){}
constructor(){
this.click = this.click.bind(this)
}
3.
click(){}
<button
onClick={this.click.bind(this)}
>
4.
click(){}
<button
onClick={(e,i)=>this.click(e)}
>
state 状态
操作状态中的数据,就能操作视图
constructor(){
this.state={num: 0}
}
操作数据不能直接使用this.state.num = 1
只能通过this.setState()去修改你的状态
this.setState({ //(推荐使用这种)
num: 3
}, () => {
console.log(this.state.num);
})
// 第二种
this.setState((state) => {
return { num: state.num + 1 }
}, () => {
console.log(this.state.num);
})
setState 是同步还是异步的?
props数据之间的通信:(单向数据流) / 生命周期
父级传子级:
传递数据在组件身上使用属性的绑定
推荐使用:
<App {...{
xxx:'hello',
bbb:'word',
ccc:[4,5,6]
}}/>
子组件接收
this.props.xxx
//以上知识点的综合应用(小todu)之 app.js(父级)
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import List from './list';
class App extends Component {
constructor(props) {
super(props);
/*
state 等同于 Vue中的data:
data() {
return {
}
}
*/
this.state = {
val: '',
arr: ['第一个li']
};
}
/*
改变数据状态使用 this.setState()
*/
change = (ev) => {
this.setState({
val: ev.target.value
})
}
keyup = (ev) => {
if (ev.keyCode === 13) {
let { arr, val } = this.state;
arr.push(val)
this.setState({ arr ,val:''});
}
}
render() {
let { val, arr } = this.state;
let list = arr.map((e, i) => { //循环产生一堆<li> </li>
return <List {...{ //map方法会返回一个新数组[<li></li>,<li></li>,...],map方法一定要return,jsx的{}会自动展开数组
key: i, //尽量保证key的值是唯一的
val: e //val和key是固定写法,val是<li>的innerText
}} />
});
return (
<div className='App'>
<input
value={val}
onChange={this.change}
onKeyUp={this.keyup}
/>
<ul>
{list}
</ul>
</div>
);
}
}
export default App;
//子组件 (list.js)
import React, {Component} from 'react'
class List extends Component{
render(){
return(
<li>{this.props.val}</li> //接收父级的数据
);
}
}
export default List;
获取DOM元素
- 给元素标记 ref
<input type="text" ref="username" onChange={this.showThis}/>
- 获取
console.log(this.refs.username.value)
父级获取子级的值和方法
下面用一个父组件(Father.js)和子组件(Child.js)来演示如何能拿到值和方法:
方法一:
给子组件添加属性 ref=‘childData’<Child ref='childData'></Child>
然后在父组件用 this.refs.childData.xxx 的方式拿值
console.log(this.refs.childData.state) // 拿到子组件中state中的值
console.log(this.refs.childData.run()) // 拿到子组件中run方法
方法二:
给子组件添加 onRef={(ref) => { this.child = ref; }}
<Child onRef={(ref) => { this.child = ref; }}></Child>
然后在子组件中添加生命周期的 componentDidMount 这个方法:
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this);
}
}
然后在父组件用 this.child.xxx 的方式拿值
console.log(this.child.state);
console.log(this.child.run();
方法三:
在父组件创建ref容器:this.pw = React.createRef()
constructor(props) {
super(props);
// 方法3:创建用来保存ref标识的标签对象的容器
this.pw = React.createRef()
}
然后给子组件添加属性:ref={this.pw}
<Child ref={this.pw}></Child>
然后就可以在父组件用 this.pw.current 拿到子组件值和方法:
console.log(this.pw.current.state);
console.log(this.pw.current.run();
空元素、空标签
react 需要在组件或其他地方加个包裹层,可能会用div包裹,但是又不想有真实的DOM节点,可以用以下空标签包裹
<React.Fragment> </React.Fragment>
<></> 它也具有非常好的速记语法,仅在最新版本(和Babel 7+)中受支持:
优化,减少不必要的 刷新(render)
查看更多
用 PureComponent 代替 Component
import React, { Component, PureComponent } from 'react';
export default class App extends PureComponent{
render() {
return(
<></>
)
}
};
强制触发 render
首先改变 state 或者 props 就可以触发组件的刷新,除此之外,react 还专门提供了一个方法this.forceUpdate()
import React, { PureComponent } from 'react';
export default class Test extends PureComponent {
componentDidUpdate() {
alert("组件刷新了");
};
render() {
return (
<button onClick={() => this.forceUpdate()}>刷新组件</button>
)
};
};