英文官网: https://reactjs.org/
中文官网:https://react.docschina.org/
基本知识
1、jsx语法
标签中使用js表达式用{}
jsx中样式叫className
内联样式使用style={{key:value}}去写
只有一个根标签
标签必须闭合
标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
<script type="text/babel">
const myid = 'testid'
const mydata = 'hello,testdata'
// 1、创建虚拟dom
const VDOM = (
<div id={myid} className="title">
<span style={{ color: "#fff" }}>{mydata}</span>
</div>
)
/* 此处一定不要写引号,因为不是字符串 */
// 2、渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</script>
2、组件
组件创建
//1.创建函数式组件
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
//1.创建类式组件
class MyComponent extends React.Component {
render(){
//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
组件实例的三大属性
state
render会调用n+1次,初始时调用一次,每次页面更新都会调用
(相当于vue中的data)
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
class Weather extends React.Component {
// 写赋值语句相当于再实例身上加属性和方法,同下面的changeWeather
state = { isHot: false, wind: '微风' }
render() {
// changeWeather加()会立即执行
return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
}
changeWeather = () => {
// 箭头函数没有this,和外层的this指向同一个,此处指向函数的实例对象
const isHot = this.state.isHot
this.setState({ isHot: !isHot })
console.log(isHot)
}
}
ReactDOM.render(<Weather />, document.getElementById('test'))
props
基本使用
class Person extends React.Component {
render() {
console.log(this)
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>年龄:{this.props.age}</li>
<li>性别:{this.props.sex}</li>
</ul>
)
}
}
// 批量传递标签属性
// const p = {name:'老刘',age:18,sex:'女'}
// {...p}
ReactDOM.render(<Person name='tom' age={18} sex='女'/>, document.getElementById('test'))
添加限制(类型限制、必填限制、数据处理)
class Person extends React.Component {
render() {
console.log(this)
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>年龄:{this.props.age + 1}</li>
<li>性别:{this.props.sex}</li>
</ul>
)
}
static propTypes = {
name: PropTypes.string.isRequired, //限制name必传,且为字符串
sex: PropTypes.string,//限制sex为字符串
age: PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
}
static propTypes = {
name: PropTypes.string.isRequired, //限制name必传,且为字符串
sex: PropTypes.string,//限制sex为字符串
age: PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
}
}
//对标签属性进行类型、必要性的限制
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//对标签属性赋值默认值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
let p = { name: 'aa'}
ReactDOM.render(<Person name='tom' age={18} sex='女' />, document.getElementById('test'))
ReactDOM.render(<Person name='jerry' age={19} sex='女' />, document.getElementById('test1'))
ReactDOM.render(<Person {...p} />, document.getElementById('test2'))
函数式组件使用
function Person (props){
const {name,age,sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
ref
请勿过度使用refs
回调形式ref如果是内连写法会调用2n+1次,初始时调用一次,每次页面更新都会清空并重新创建;如果是写ref={funcname}
则会只是在初始时候调用一次
字符串形式的ref会有性能上的问题,16版本后使用回调形式的ref
class Demo extends React.Component {
showData = () => {
// 字符串形式的refs
const {input1} = this.refs
alert(input1.value)
}
showData2 = ()=>{
// 回调函数形式的refs
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据" />
<button onClick={this.showData}>点我提示左侧的数据</button>
<input ref={c=>this.input2=c} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
</div>
)
}
}
jsx在结构中的注释方式是:{/* */}
括号中表明写的是js表达式
createRef的使用,因为是“专人专用”,所以每次都需要重新写一个ref
/*
React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
*/
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = ()=>{
alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = ()=>{
alert(this.myRef2.current.value);
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
不要过度使用ref,可以通过evvent.target
获取节点身上的属性
受控与非受控组件
数据现用现去是非受控组件
受控组件是随时把数据维护到状态里,需要的时候直接从状态里面去取,相当于vue的双向数据绑定
尽量使用受控组件,可以减少使用refs
柯里化函数
高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、arr.map()等等
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
function sum(a){
return(b)=>{
return (c)=>{
return a+b+c
}
}
}
//初始化状态
state = {
username:'', //用户名
password:'' //密码
}
//保存表单数据到状态中
saveFormData = (dataType)=>{
return (event)=>{
this.setState({[dataType]:event.target.value})
}
}
//表单提交的回调
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render(){
// saveFormData方法加上()表明是把saveFormData的返回函数赋给onChange方法
return(
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
<button>登录</button>
</form>
)
}
3、生命周期
旧生命周期(18之前)
-
初始化阶段: 由ReactDOM.render()触发—初次渲染
1. constructor() 2. componentWillMount() 3. render() 4. <mark> componentDidMount()</mark> =====> 常用 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 2. 更新阶段: 由组件内部this.setSate()或父组件render触发 1. shouldComponentUpdate() 2. componentWillUpdate() 3. <mark> render()</mark> =====> 必须使用的一个 4. componentDidUpdate() 3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发 1. <mark>componentWillUnmount()</mark> =====> 常用 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
新生命周期(18及其之后)
-
初始化阶段: 由ReactDOM.render()触发—初次渲染
1. constructor() 2. getDerivedStateFromProps(了解) 3. render() 4. componentDidMount() =====> 常用 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发 1. static getDerivedStateFromProps:用于state的值在任何时候都取决于props,横跨挂载和更新(了解) 2. shouldComponentUpdate() 3. render() 4. getSnapshotBeforeUpdate:返回值传递给下面,作为第三个参数 5. componentDidUpdate(preProps,preState,传递的参数) 3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发 1. componentWillUnmount() =====> 常用 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
注意:react正在研究异步渲染,避免使用三个初始化和更新中带will的生命周期钩子,后续可能会被去掉
重要的钩子
1.render:初始化渲染或更新渲染调用
2.componentDidMount:开启监听, 发送ajax请求
3.componentWillUnmount:做一些收尾工作, 如: 清理定时器