react入门
简介
react是有Facebook团队建设的于13年5月份开源
react框架定位:只是MVC框架里面的视图层
特点:声明式,组件化,一次学习随处编写
react在16.x版本之后推出fiber协调算法,解决之前的diff算法同步的进行更新操作,导致浏览器卡顿的问题。内部采分片思想实现的
安装
npm i react react-dom babel-standlone
安装所需要的包,然后在node_modules中分别找到相对应的文件夹,将里面的js文件复制到自己新建的js文件中
然后在HTML中引入这些文件
<!-- 引入react核心包 如果需要使用react 这个包必须在最前面 不然后续无法识别react内相关的语法 -->
<script src="./js/react.development.js"></script>
<script src="./js/react-dom.development.js"></script> <!-- 注意这里两个js文件的引入顺序一定不能出错 -->
<script src="./js/babel.js"></script> //babel包主要就是用来解析jsx代码的
然后就可以使用react来写代码了
<body>
<div id="app"></div>
<script type="text/babel">
// console.log(ReactDOM)
// jsx代码 JavaScript + xml语法
//如果要使内容呈现为h2下的样式就需要引入babel(解析jsx代码的包),同时要在script标签上加 type="text/babel"
//如果没有这些条件的话 页面会报错 “<” 未识别
ReactDOM.render(<h2>hello react</h2>,document.getElementById("app"))
</script>
</body>
ReactDOM.createElement(核心)
jsx内部的原理是什么?
首先jsx内部通过babel将jsx代码进行解析(ReactDOM.createElemnet)–> 虚拟dom ---->ReactDOM.render() 将虚拟dom渲染成真实dom
在这里就要注意一个问题就是,引入babel后再script标签内就要加入type=“text/babel” 这个属性以及属性值class属性的使用方法
const a = <h2 class="app">H2!!</h2> //如果里面用class属性的话,虽然不影响页面的渲染,但是会报错,会被当成一个保留字,推荐使用className
const a = <h2 className="app">H2!!<span>SPAN!!<a>A!</a></span></h2>
//jsx语法糖 替代React.createElement()
// 这种写法可以直接不需要babel,但是这样写有个问题就是,当里面嵌套的标签多了以及内容多了之后,写起来会变得很麻烦
const a = React.createElement("h2",{className:"app"},"H2!!",
React.createElement("span",{},"嵌套在h2里面的SPAN!!",
React.createElement("a",{},"嵌套在span里面的a!!")))
ReactDOM.render(a,document.getElementById("app"))
这个必须加,如果不用这个方法的页面上是无法渲染页面的,当然内部的“a”也可以直接用HTML语言代替,但是要遵循一个规则就是其中的标签必须闭合,包括单标签,例如;有且只有一个根元素;jsx内部注释写法为{/* 注释*/}
react内部样式写法
在标签内使用style标签的时候要注意的就是,在这里需要用到的是双大括号(内部的大括号是个对象),同时内部value值需要加单引号,key需要驼峰式命名或者是正常命名但是要加单引号,但是推荐使用驼峰式命名方法,用’text-align’:'center’这种写法页面会报错提醒你换成textAlign
const a = <div style={{background:'skyblue',color:'red',fontSize:'40px','text-align':'center'}}>style样式使用</div>
ReactDOM.render(a,document.getElementById("app"))
react表达式
react中可以通过{}方式渲染变量
{}中放入数组会自动进行字符产拼接
{}中放入布尔值,undefined null 页面不会进行渲染直接为空,且不占位
{}中放入对象直接拨错
{}中可以放入函数,但是需要用闭包的形式,也就是(函数声明)(函数调用)
react事件绑定
当两种点击方法同时存在的时候,先触发的是document.getElement(“a”).onclick事件,同时这个方法必须要在放在render之后
如果在render前面的话直接报错,因为此时的页面还没有渲染出div标签,所以也就无法获取到id
利用函数的形式绑定事件的时候,要注意的是在标签内绑定事件的时候用的是驼峰式命名方法,同时引入事件也需要加{}
function click(){
alert(1)
}
const a = <div id="a" onClick={click}>我是a</div>
ReactDOM.render(a,document.getElementById("app"))
document.getElementById("a").onclick = function(){
alert(2)
}
数组的map遍历
[注意!!]下面两个问题可能会是面试题
vue中通过指令v-for可以进行数组或对象的遍历,在react中如何遍历数组?
react里面是没有提供任何指令!
jsx中遍历数组可以通过map方法进行遍历!
数组的遍历迭代需要注意什么?加key?为何加key?
key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。
key值相同的节点是会复用!
key还不容易报错!尽量不要使用index作为下标! 容易有误差,除非index值一直保持不变,同时内部元素不会发生任何改变
const arr = [1,2,3]
ReactDOM.render(<div>{
arr.map((item,index)=>{return <p key={index}>{item}</p>})
}</div>,document.getElementById("app"))
</script>
多数组遍历
当需要遍历多个数组的时候,可以直接将map方法封装成一个函数,用的时候直接调用就行
【注】在封装函数的时候记住一定要有return返回值,如果没有返回值的话,最后调用的时候值就是undefined,这样页面也就不会进行渲染,同时还要注意的就是,如果return后面不加()的话,那么后面一定要跟着表达式,不然会被判定没有return返回值
const arr = [1,2,3]
const arr2 = ['a','b','c']
function mapArr(arr){
return arr.map(
(item,index)=>{
return <p key={index}>{item}</p>
})
}
ReactDOM.render(<div>
{
mapArr(arr)
}
{
mapArr(arr2)
}
</div>,document.getElementById("app"))
数组遍历绑定事件
因为react是一个视图层,所以不会像vue一样当数据发生改变后,视图层也跟着数据的改变而重新渲染,所以这时候就需要将ReactDOM.render封装成一个函数,然后绑定在点击事件上,这样每次数据发生了改变后,就要重新在走一遍render函数,这样页面也就完成了重新的渲染,相较于vue来说比较麻烦
let currentIndex = 0
let arr = ['a','b','c']
function mapArr(arr){
return(
<ul>
{
arr.map((item,index)=>{return <li key={index}
className={index == currentIndex?'active' : ''}
onClick={()=>{currentIndex = index;render()}}
>{item}</li>})
}
</ul>
)
}
render() //需要调用一次,来渲染初始的页面,如果不调用的话直接渲染不出页面来
function render() {
ReactDOM.render(<div>
{
mapArr(arr)
}
</div>,document.getElementById("app"))
}
定义组件方式
函数式
const 组件名(首字母大写)=(props)=>{
return jsx表达式
}
注意:组件名的首字母必须大写
利用组件定义,可以在其内部做一些类似于vue中v-show和v-if的操作
之所以是下面的写法的原因可以参考map数组遍历中的事件绑定,主要原因就是因为react只是一个视图层没有双向数据绑定,无法实时监听到数据的改变
第一种显示隐藏的写法,第二种请看class组件定义
let isShow = true //注意,这里不能用const去定义要修改的变量,因为const定义的变量不能修改
const App = (props) => {
return (
<div>
<button onClick={()=>{isShow=!isShow;render()}}>切换</button>
<div className={isShow? 'block' : 'none'}>我是APP组件</div>
</div>
)
}
render()
function render(){
ReactDOM.render(<App/>,document.getElementById("app"))
}
函数式定义组件中的属性
注意:组件名的首字母必须大写,这里面不需要this,直接使用传参拿数据就ok
const App = (props) => {
console.log(this) //undefined 是没有属性的
return (
<div>
APP组件 --- {props.name}
</div>
)
}
let obj = {
name:"张三",
age:10,
sex:"男"
}
//可以在<App name={"张三"}/>中直接添加
render()
function render(){
ReactDOM.render(<App {...obj}/>,document.getElementById("app"))
}
class定义组件
两种组件方式:第二种,class定义
class 组件名 extends React.Component {
render(){ //render是必不可少的钩子函数
return jsx表达式
}
}
这是第二种显示隐藏写法,第一种在函数式写法里面
let isShow = true
class App extends React.Component{
render(){ //render这个钩子函数必须要有
return (
<div>
<button onClick={()=>{isShow=!isShow;render()}}>切换</button>
{/*这是第二种写法,不需要用className了直接用style属性就可以,需要注意的就是要双括号,这里模拟的是vue中的v-show指令*/}
{/*<div style={{display:isShow? 'block' : 'none'}}>我是APP组件</div>*/}
{/*这里模拟的是v-if的效果*/}
{/*{!isShow || <p>我是APP组件</p>} 前面为假所以执行后面的代码*/}
{isShow && <p>我是APP组件</p>} {/*这个与上面的相反,真的时候才走后面的代码,为假直接为假*/}
</div>
)
}
}
render()
function render(){
ReactDOM.render(<App/>,document.getElementById("app"))
}
class组件定义的属性
第一种写法
class App extends React.Component{
render(){ //render这个钩子函数必须要有
console.log(this) //可以参考如下图片
return (
<div>
<p>我是APP组件 ----- {this.props.name}----{this.props.age}</p>
</div>
)
}
}
render()
function render(){
ReactDOM.render(<App name={"张三"} age={18}/>,document.getElementById("app"))
}
第二种写法
let obj = {
name:"张三",
age:18,
sex:"男"
}
class App extends React.Component{
render(){ //render这个钩子函数必须要有
console.log(this)
return (
<div>
<p>我是APP组件 ----- {this.props.name}----{this.props.age}</p>
</div>
)
}
}
render()
function render(){
ReactDOM.render(<App {...obj}/>,document.getElementById("app"))
}