React是用于构建用户界面的JavaScript库(只关注视)
声明式编程:React 使创建交互式 UI ,当数据变动时 React 能高效更新并渲染合适的组件。
组件化: 构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI。
高效:React通过对DOM的模拟,最大限度地减少与DOM的交互。
灵活:无论你现在使用什么技术栈,都可通过引入 React 来开发新功能。
使用虚拟(virtual)DOM,不总是直接操作页面真实DOM。
DOM Diffing算法,最小化页面重绘
说明:React并不会提高渲染速度,反而可能会增加渲染时间,真正高效的原因是它能有效减少渲染次数
。
本质时Object类型的对象(一般对象)
虚拟DOM比较’轻’,真实DOM比较’重’,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性(只有React需要的属性)
虚拟DOM最终会被React转化为真实DOM,呈现在页面上
1、首先创建一个html文件,用IDE工具打开,引入react核心库 、react 扩展库、编译jsx为js的库,如下
<!-- react核心库 -->
<script src="js/react.development.js"></script>
<!-- react 扩展库 操作dom元素 -->
<script src="js/react-dom.development.js"></script>
<!-- 编译jsx的一个语法 -->
<script src="js/babel.min.js"></script>
2、在html文件中创建一个容器,然后创建虚拟DOM并渲染到页面上,代码如下
<div id="demo"></div>
<script type="text/babel">
//创建虚拟DOM 1如果是单行 不需要加()如果是多行用()
let str = "hello,react";
//混入js表达式用{},class样式用className
const VDEMO =(
<h111 className="demo" style={{background:'red',color:'green',fontSize:'40px'}}>
<span>{str}</span>
<p>{str}</p>
</h111>
)
//渲染虚拟dom到页面上
ReactDOM.render(VDEMO,document.getElementById("demo"));
</script>
注意此处的script便签要注明类别,因为我们用的是jsx语法
3、hello,react成功出现在页面上
JSX是一种JavaScript的语法扩展、是一种嵌入式的类似XML的语法,常应用于React架构中,但也不仅限于此.
语法规则:
1、定义虚拟DOM时不要用引号
错误示例:
let V_DOM = ‘<h1>hello,react</h1>’;
2、标签混入JS表达式需要用{}
举例:
let str = "hello,react!";
let V_DOM = (
<h1><span>{str}</span></h1>
)
3、样式的类名指定不要用class,要用className
示例:
let V_DOM = (
<h1 className='demo'><span>我是文本内容</span></h1>
)
4、内联样式要用style={{key:value}}的形式(双{}代表对象,单{}代表表达式
)去写。
示例:
let V_DOM = (
<h1 className='demo'><span style={{color:'blue',fontSize:'30px'}}>我是文本内容</span></h1>
)
ReactDOM.render(V_DOM,document.getElementById("hello"));
5、只有一个根标签
错误形式:
let V_DOM = (
<h1 className='demo'><span style={{color:'blue',fontSize:'30px'}}>我是文本内容</span></h1>
<p>我是段落</p>
)
6、标签必须闭合
举例:
<input type=”text” name=’myname’ value=’’></input>
7、标签首字母
若小写字母开头
,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
。
若大写字母开头
,react就去渲染对应组件,若组件没有定义,则报错
。
8、不能放在创建虚拟dom语句中的js语句
if(){}
for(){}
switch(){}
基本应用:
function Person(){
// console.log(typeof obj.age);//查看类型
return <h1>姓名:张三,年龄:19</h1>
}
ReactDOM.render(<Person/>,document.getElementById('demo'));
组件传参:
function Person(obj){
// console.log(typeof obj.age);//查看类型
return <h1>姓名:{obj.name},年龄:{obj.age}</h1>
}
ReactDOM.render(<Person name="张三" age={19}/>,document.getElementById('demo'));
组件复用:
function GetName(obj){
return <li>姓名:{obj.name}</li>
}
function GetAge(obj){
return <li>年龄:{obj.age}</li>
}
function Person(){
return (
<ul>
<GetName name='张三'/>
<GetAge age='19'/>
</ul>
)
}
ReactDOM.render(<Person/>,document.getElementById('demo'));
1:继承react中的Component类
2:需要render
基本应用:
class Person extends React.Component{
render(){
return (
<h1>你好,我是类式组件!</h1>
)
}
}
ReactDOM.render(<Person/>,document.getElementById("hello"));
小例子:
class Item extends React.Component {
data = [
{ name: '张三', age: 11, index: 0 },
{ name: '李四', age: 12, index: 1 },
{ name: '王五', age: 13, index: 2 },
{ name: '铁柱', age: 14, index: 3 },
{ name: '李华', age: 15, index: 4 },
{ name: '李明', age: 16, index: 5 },
]
render() {
return this.data.map(v => {
return (
<li
key={v.index}
className={v.index % 2 == 0 ? 'oushu' : 'jishu'}
>
姓名:{v.name}——年龄:{v.age}{' '}
</li>
)
})
}
}
class Person extends React.Component {
name = '111'
render() {
return (
<ul>
<Item />
</ul>
)
}
}
//渲染虚拟dom到页面上
ReactDOM.render(<Person />, document.getElementById('demo'))
概念:state是组件对象最重要的属性,值是对象(可以包含多个key:value的组合),组件被称为状态机
,通过更新组件的state来更新对应的页面显示(重新渲染组件),有state称为复杂组件。
State 的使用对象形式(key,value);
代码:
class MyClass extends React.Component{
constructor(props) {
super(props);
this.state = {isflag:true};
}
render(){
return <a href='javascript:;' className='btn'>{this.state.isflag?'已关注':'取消关注'}</a>
}
}
ReactDOM.render(<MyClass/>,document.getElementById('hello'));
react绑定事件:
说明:
·onclick 变为 onClick。
·{函数名}返回值给click,加()就会直接调用。
例:
render(){
return <a href='javascript:;' onClick={demo} className='btn'>{this.state.isflag?'已关注':'取消关注'}</a>
}
修改state值:
class MyClass extends React.Component{
constructor(props) {
super(props);
this.state = {isflag:true};
this.demo = this.demo.bind(this);
}
render(){
return <a href='javascript:;' onClick={this.demo} className='btn'>{this.state.isflag?'已关注':'取消关注'}</a>
}
demo(){
this.setState({isflag:!this.state.isflag})
}
}
ReactDOM.render(<MyClass/>,document.getElementById('hello'));
说明:
·bind会生成一个新的方法 并传对象 改变this的指向
·必须使用setState 修改才有效,修改内容为合并。有值得修改没有的不动
· 每个组件对象都会有props(properties的简写)属性。
· 组件标签的所有属性都保存在props中。
· props 是不可变的,只能通过 props 来传递数据。
class Person extends React.Component{
render(){
const {name,age} = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
ReactDOM.render(<Person name='张三' age='18'/>,document.getElementById('hello'));
propTypes参数的限制:
需要引入依赖包:
class Person extends React.Component{
render(){
const {name,age,sex} = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
static propTypes = {
name:PropTypes.string.isRequired,//必填且为字符串型
age:PropTypes.number,//数值型
}
static defaultProps = {
sex:'未知',
}
}
定义:组件内的标签可以定义ref来标识自己。
ref有三种用法:
1):字符串形式的ref
class MyRefs extends React.Component{
showData = ()=>{
//字符串形式的ref
let input1 = this.refs.input1;
alert(input1.value);
}
showData2 = ()=>{
let input2 = this.refs.input2;
alert(input2.value);
}
render(){
return (
<div> <input ref="input1" type="text" placeholder="点击时提示信息" /><br/><br/>
<input onClick={this.showData} type="button" value="点击显示信息"/><br/><br/>
<input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点时显示信息" />
</div>
)
}
}
}
2):回调函数形式的ref
class Demo extends React.Component{
showData = ()=>{
//回调函数下创建ref
const {input1}=this;
console.log(input1.value);
}
showData2 = ()=>{
const {input2}=this;
console.log(input2.value);
}
render(){
return (
<div>
<input ref={c=> this.input1 = c} type="text" placeholder="点击时提示信息" /><br/><br/>
<input onClick={this.showData} type="button" value="点击显示信息"/><br/><br/>
<input ref={c=> this.input2 = c} onBlur={this.showData2} type="text" placeholder="失去焦点时显示信息" />
</div>
)
}
}
3):类绑定形式下ref
class MyRefs extends React.Component{
userInput = React.createRef();
passInput = React.createRef();
showData = ()=>{
//createRef创建ref 官方推荐
const {userInput,passInput} = this;
const str = `用户名是${userInput.current.value},密码是:${passInput.current.value}`;
console.log(str);
}
//显示个性签名
showmessage = (e)=>{
console.log('message:',e.target.value);
}
render(){
return (
<div>
<ul className="list">
<li><input ref={this.userInput} type="text" placeholder="请输入用户名"/> </li>
<li><input ref={this.passInput} type="password" placeholder="请输入密码"/> </li>
<li><input type="button" onClick={this.showData} value="查看信息"/> </li>
<li><input type="text" onKeyUp ={this.showmessage} placeholder="请输入个性说明"/> </li>
</ul>
</div>
)
}
}
class Control extends React.Component {
showdata = () => {
// 现取现用,非受控组件
console.log(this.name.value)
console.log(this.age.value)
}
render() {
return (
<ul>
<li>
<input
type="text"
ref={e => (this.name = e)}
></input>
</li>
<li>
<input
type="text"
ref={e => (this.age = e)}
></input>
</li>
<button onClick={this.showdata}>显示数据</button>
</ul>
)
}
}
class Control1 extends React.Component {
state = { name: '', age: '' }
// 将值存储到state里面,按需取用,受控组件
saveName = e => {
// console.log(e.target.value)
this.setState({name:e.target.value})
}
saveAge = e => {
// console.log(e.target.value)
this.setState({age:e.target.value})
}
showdata=()=>{
console.log(this.state)
}
render() {
return (
<ul>
<li>
<input
type="text"
onChange={this.saveName}
></input>
</li>
<li>
<input
type="text"
onChange={this.saveAge}
></input>
</li>
<button onClick={this.showdata}>显示数据</button>
</ul>
)
}
}
高阶函数
定义:如果一个函数符合下面两个规范中的任何一个,那该函数就是高阶函数
·若A函数,接受的参数是一个函数,那么A就可以称之为高阶函数
·若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数
常见的高阶函数有:Promise、setTimeout、arr.map()等等
代码示例:
class Demo extends React.Component{
//初始化状态
state = {username:'',password:''};
savedata = (dataType)=>{
return (event)=>{
this.setState({[dataType]:event.target.value});
}
}
showdata = (event)=>{
event.preventDefault();//阻止默认事件
let {username,password} = this.state;
alert(username + '-' + password);
}
render(){
return (
<form action="" onSubmit={this.showdata}>
用户名: <input onChange={this.savedata('username')} type="text" name="username"/><br/>
密 码:<input onChange={this.savedata('password')} type="password" name="password"/><br/>
<input type="submit" name="dosubmit" value="提交信息"/>
</form>
);
}
}
分析上面的代码,会发现组件内的绑定事件后面加了括号传值,而前面的语法部分说了方法名后面加了括号就是直接调用执行,这时候就体现高阶函数的作用了,我们把函数单独拿出来
savedata = (dataType)=>{
return (event)=>{
this.setState({[dataType]:event.target.value});
}
}
注意看函数的返回值,返回了一个函数,所以绑定事件直接调用之后返回了一个函数,这个函数才是我们需要去出触发的方法,我们做的只是用同一个函数根据不同的传值来返回代码几乎一样的方法,节省了代码量
·组件从创建到死亡,会经过一些特定的阶段。
·React组件中包含一系列钩子函数{生命周期回调函数},会在特定的时刻调用。
·我们在定义组件的时候,会在特定的声明周期回调函数中,做特定的工作。
由ReactDOM.render()触发,一般在这个钩子中做一些初始化的事情,如:开启定时器,发送网络请求,订阅消息等。
·constructor() 构造方法:构造函数最先执行,用处:进行初始化的一些数据
·componentWillMount() 即将挂载
·render() 组件渲染
·componentDidMount() ==>常用
组件将要渲染
由组件内部的this.setState()或者父组件的render触发。
·shouldComponentUpdate() 组件应该更新:阀门,当更新的时候,受其控制,true就让更新,false就不让更新
shouldComponentUpdate(){
console.log("Count shouldCompenentUpdate---");
return true;
}
·componentWillUpdate() 组件将要更新
·render() ===>必须使用
的一个
·componentDidUpdate() 组件将要更新
由ReactDOM.unmountComponentAtNode(卸载节点上的组件
)触发,一般在这个钩子中做一些首位的事情,如:关闭定时器,取消订阅等
·constructor()
· getDerivedStateFromProps()
state里面的内容由props控制。如果全部控制 就return props 部分更改,return对象里面写要更改的数据
在render之前调用
此钩子 是静态方法 必须有返回值
static getDerivedStateFromProps(props){
console.log("Count getDerivedStateFromProps----");
return {title:props.title};
}
·render()
·componentDidMount() ====>常用
·getDerivedStateFromProps() 从Props获得派生状态
· shouldComponentUpdate() 组件应该更新
·render()
·getSnapshotBeforeUpdate() 在更新前获得快照
·componentDidUpdate()
由ReactDOM.unmountComponentAtNode()触发
常用
- render:初始化渲染或者更新渲染调用
- componentDidMount() :开启监听,发送ajax请求
componentDidMount(){
let {count} = this.state;
this.myinter = setInterval(()=>{
count++;
this.setState({count:count})
},1000)
}
- componentWillUnmount(): 做一些收尾工作,如:清理定时器
componentWillUnmount(){
//清除定时器
clearInterval(this.myinter);
}
ps
:现在使用会出现警告,之后版本可能需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用