React快速入门
不使用脚手架
引入js:
<script src="./js/react.development.js"></script><script src="./js/react-dom.development.js"</script>
写法:
<div id="root"></div>
<script>
//创建标签
let h1=React.createElement('h1',{name:'h1-name',price:200},'当前h1标签的内容')
let root=document.querySelector("#root");
ReactDOM.render(h1,root);//挂载(标签,挂载位置)
</script>
这样即可实现div的id为root标签上放入h1标签
脚手架
安装与创建项目并启动
老式安装方法:
cnpm install -g create-react-app //安装
create-react-app 项目名称 //创建项目
推荐使用的安装chai方法
//npx无需先安装脚手架(推荐使用)
npx create-react-app 项目名 //有就会直接创建,没有则会安装再创建
启动项目:
npm start //启动
简单使用
在脚手架创建完项目后,在index.js(入口文件)进行操作
当然也可以新建一个js操作,不过需要在入口文件导入…
const root = ReactDOM.createRoot(document.getElementById('root'));//得到dom元素
//使用函数进行创建dom
function Hello(props){ //函数名必须要大写开头
return <h1>helloworld</h1>;
}
//挂载
root.render(
<Hello />
);
//方式2
//let root=document.querySelector("#root");
//ReactDOM.render(<Hello />,root)
以上代码即可实现页面显示的内容为h1标签的helloworld
JSX
React 使用 JSX 来替代常规的 JavaScript。
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
我们不需要一定使用 JSX,但它有以下优点:
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
- 它是类型安全的,在编译过程中就能发现错误。
- 使用 JSX 编写模板更加简单快速。
使用className定义类名
简单的
//jsx
//简易的jsx
const title=<h1 price="200">Hello React~</h1>
root.render(
title
)
复杂的
通过{}获取变量值
使用()将多个复杂层次的标签包裹起来
//复杂的jsx
let name='碰磕'
let age=18
let div=(
<div className='box'>
<h1>hello JSX</h1>
<p style={{'color':"red"}}>name={name},年龄={age}</p>
</div>
)
//挂载
root.render(
div
)
条件渲染
通过函数判断返回的内容并显示
//条件渲染
let flag=true;
function Login(user){
if(flag){
return <u>欢迎{user}登录</u>
}
return <u>还没登录呢</u>
}
const div=(
<div>
<h1>条件渲染</h1>
{Login('碰磕')}
</div>
)
循环
简单的循环数组
//循环
const number=[1,23,312,23,66];
//这里演示map方法,当然还有很多种
let ok =number.map((num)=>{
return <li>{num}</li>; //jsx写法
})
root.render(
<ul>{ok}</ul>
)
循环数组中的对象(常见)
const sz=[
{uid:1,uname:'碰磕'},
{uid:2,uname:'Student'},
{uid:3,uname:'Study'}
]
let ok2 =(
<div className='box' >
<ul>
{sz.map((val)=>{
return <li key={val.uid}>uid:{val.uid},uname:{val.uname}</li>;
})}
</ul>
</div>
)
root.render(
ok2
)
组件的三种定义方式
因为是组件,所以挂载时都要加上标签
例如Fun则是
root.render( <Fun /> )
函数组件
函数组件中的事件在组件内定义
通过{事件名}调用
//函数组件
function Fun(){
//点击函数
function dj(){
alert('点我干啥??')
}
return (
<div className='box'>
<b>我是组件,可重复利用</b>
<button onClick={dj}>Click</button>
</div>
)
}
root.render(
<Fun />
)
类组件
语法:class 组件名 extends React.Component{
render(){
return()
}
}
类组件的组件在类内定义,通过this.事件名调用
//类组件 class Box2 extends React.Component{ dj(){ alert('我是类组件') } //渲染 render(){ return( <div className='box'> <b>我是组件2,可重复利用</b> <button onClick={this.dj}>Click</button> </div> ) } } root.render( <Box2 /> );
独立定义类组件(常用)
创建一个文件Box.js在该文件内定义
import React from "react" //类组件 class Box3 extends React.Component{ dj(){ alert('我是类组件独立文件') } render(){ return( <div className='box'> <b>我是组件3,可重复利用</b> <button onClick={this.dj}>Click</button> </div> ) } } export default Box3//导出
在入口文件导入并使用:
import Box3 from './Box' const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Box3 /> );
这样即可使用成功~
state(用于绑定数据)
简单应用
完成计算器,+或者-改变数据,并且可通过函数传参
- 可以在构造方法里边定义state也可以在构造方法外部定义
- 获取state数据:this.state.属性名
- 修改state数据:this.setState({})-------类似微信小程序写法
- 传参函数this.函数名.bind(this,参数)----->必须传一个this
Tip:需要使用箭头函数,this指向问题-普通函数拿不到this,通过this得到state
class NumberCount extends React.Component{
//构造方法
constructor(){
super();
this.state={
count:66
}
}
//由于this在普通函数为undefined,所以改为箭头函数
jia=()=>{
//不能直接更新
// this.state.count=this.state.count+1
this.setState({ //类似于微信小程序写法
count:this.state.count+1
})
}
//传参函数,参数中必须带this,通过bind进行传参
jian=(num)=>{
console.log("num=",num);
}
//渲染
render(){
return(
<div>
<h1>计数器</h1>
<h3>{this.state.count}</h3>
<button onClick={this.jia}>+1</button>
<button onClick={this.jian.bind(this,4)}>-</button>
</div>
)
}
}
export default NumberCount;
导出后在index中使用即可
表单与状态绑定的应用
实现类似vue中的双向绑定,通过修改表单中的值,state的值也会跟着变
**Tip:**文本框被改变事件不绑定会报错
/**
* 表单--绑定-->状态
*/
import React from 'react';
import ReactDOM from 'react-dom/client';
class Mytxt extends React.Component{
state={
stname:'temo',
city:'吉安市',
area:'江西省',
flag:true
}
//文本框被改变事件(不绑定会报错)
txthandle=(e)=>{
//绑定stname值(实现vue中的双向绑定)
this.setState({
stname:e.target.value
})
console.log(e.target.value);
}
areahandle=(e)=>{
this.setState({
area:e.target.value
})
console.log(this.state.area);
}
selhandle=(e)=>{
this.setState({
city:e.target.value
})
console.log(this.state.city);
}
checkhandle=(e)=>{
this.setState({
flag:e.target.checked
})
console.log(this.state.flag);
}
render(){
return(
<div>
<h1>表单测试</h1>
<p>输入框:<input onChange={this.txthandle} type='text' value={this.state.stname} /></p>
<p>文本域:<textarea onChange={this.areahandle} value={this.state.area}></textarea></p>
<p>
下拉列表-城市选择:
<select onChange={this.selhandle} value={this.state.city}>
<option value="南昌市">南昌市</option>
<option value="宜春市">宜春市</option>
<option value="吉安市">吉安市</option>
</select>
</p>
<p>
复选框:<input type="checkbox" checked={this.state.flag} onChange={this.checkhandle} />是否选择
</p>
</div>
)
}
}
export default Mytxt
优化(将所有函数合并一个函数)
上方表单每个组件都对应一个函数,看着都不雅观,上方代码可发现:
- 除了下拉框其它都是修改value
- 由此得出可以通过属性传值修改对应的state属性
- 开始实现~
/**
* 优化表单绑定的处理函数 ----多个组件用同一个
*/
import React from 'react';
import ReactDOM from 'react-dom/client';
class Mytxt2 extends React.Component{
state={
stname:'temo',
city:'吉安市',
area:'江西省',
flag:true
}
//统一处理
formhadle=(e)=>{
let t=e.target;//获取目标对象
let val=t.type == 'checkbox'?t.checked:t.value//如果市复选框则是checked,其他的是value
this.setState({
[t.name]:val
})
console.log(this.state.area);
}
render(){
return(
<div>
<h1>表单测试</h1>
<p>输入框:<input name="stname" onChange={this.formhadle} type='text' value={this.state.stname} /></p>
<p>文本域:<textarea name="area" onChange={this.formhadle} value={this.state.area}></textarea></p>
<p>
下拉列表-城市选择:
<select name="city" onChange={this.formhadle} value={this.state.city}>
<option value="南昌市">南昌市</option>
<option value="宜春市">宜春市</option>
<option value="吉安市">吉安市</option>
</select>
</p>
<p>
复选框:<input name="flag" type="checkbox" checked={this.state.flag} onChange={this.formhadle} />是否点赞
</p>
</div>
)
}
}
export default Mytxt2
通过name属性传对应的value所绑定的state中对应的属性
再用三元表达式对复选框的进行一个判断从而一一对应的修改
练习:实现留言板
思路:
- state中的属性讲解:
- gname:留言昵称
- gmsg:留言内容
- guestbookAllmsg:存放留言信息的数组
- 函数讲解:
- addmsg():发表留言,每发表留言都对guestbookAllmsg数组进行改变
- isHave():实时判断留言板是否有留言从而显示对应的内容
- 没有留言则显示:暂无评论,快去评论吧~
- 有留言则循环使用无序列表显示留言(遍历数组)
/**
* 留言板
*/
import React from 'react';
import './index.css'
class GuestBook extends React.Component{
state={
gname:'',
gmsg:'',
guestbookAllmsg:[]
}
formhadle=(e)=>{
let t=e.target;//获取目标对象
let val=t.type == 'checkbox'?t.checked:t.value//如果市复选框则是checked,其他的是value
this.setState({
[t.name]:val
})
}
//发表留言
addmsg=(e)=>{
if(this.state.gname!=""&&this.state.gmsg!=""){
let guest={
'gname':this.state.gname,
'gmsg':this.state.gmsg
}
this.setState({
guestbookAllmsg:[guest,...this.state.guestbookAllmsg]
})
console.log(this.state.guestbookAllmsg);
return;
}
alert("不能为空!")
}
isHave(){
if(this.state.guestbookAllmsg.length==0){
return <h2>暂无评论,快去评论吧~</h2>
}
let ok=this.state.guestbookAllmsg.map((msg)=>{
return <li key={msg.gmsg}>评论者:{msg.gname}<br/>评论消息:{msg.gmsg}</li>; //jsx写法
})
return <ul>{ok}</ul>
}
render(){
return(
<div className='box'>
<h1>留言板</h1>
<input type="text" name='gname' onChange={this.formhadle} value={this.state.gname} placeholder="请输入评论人昵称" />
<textarea onChange={this.formhadle} name='gmsg' value={this.state.gmsg} placeholder='评论消息'></textarea>
<button onClick={this.addmsg}>发表</button>
<div style={{'background':'pink'}}>{this.isHave()}</div>
</div>
)
}
}
export default GuestBook
通过以上练习完美的进行总结~
组件传递
父传子
通过属性传值
子组件通过this.props.属性名接收
可以传多种类型值,为了省写代码,可对this.props进行解构
案例1
import React from "react";
/**
* 父传子
*/
class Hello extends React.Component{
constructor(props){
//不传则是undefined
super(props)
console.log('构造方法',this.props);
}
render(){
let {stname,age,hobby,fun,tag}=this.props;//解构
return(
<div>
<h1>组件传参</h1>
<p>字符串{this.props.stname}</p>
<p>字符串2:{stname}年龄:{age+2}</p>
<p>数组:{hobby}</p>
<button onClick={fun}>点我触发传来的函数</button><br/>
标签:{tag}
</div>
)
}
}
export default Hello
index.js则需要引入Hello并且进行属性传值
<Hello stname='碰磕' age={18} hobby={['吃饭','睡觉','学习']} fun={()=>{alert('传过来的函数~')}} tag={<h1>我是传来的标签</h1>} />
案例2
//父传子通过属性传值...
class Parent1 extends Component{
state={
data:'碰磕'
}
render(){
return(
<div>
<div>我是父组件</div>
<Child baba={this.state.data}></Child>
</div>
)
}
}
class Child extends Component{
render(){
return(
<div>我是子组件:{this.props.baba}</div>
)
}
}
export default Parent1
子传父
父亲传递回调函数给子,子接收该函数并且调用它进行传值给父亲
//子传父
class Parent extends Component{
state={
gift:null
}
//回调函数
callback=(obj)=>{
console.log(`收到礼物:${obj}`);
this.setState({
gift:obj
})
}
render(){
let {gift} =this.state;
return(
<div>
<h3>我的礼物:{gift}</h3>
<hr/>
<Child1 gifts={this.callback}></Child1>
</div>
)
}
}
class Child1 extends Component{
state={
gift:'脑白金'
}
songgift=()=>{
this.props.gifts(this.state.gift) //调用父亲的函数并进行传值
}
render(){
let {gift} =this.state;
return(
<div>
<h3>我是子组件</h3>
<button onClick={this.songgift}>向父亲送礼</button>
</div>
)
}
}
export default Parent
兄弟传值(综合练习)
要求:儿子Tom给Jerry送礼
思路:Tom先给父亲,再由父亲转交给Jerry
import React, { Component } from "react";
//tom--->jerry parent3(中转站)
class Parent3 extends Component{
state={
gift:null
}
callback=(opt)=>{
console.log("收到给jerry的礼物",opt,"正在发送....");
this.setState({
gift:opt
})
}
render(){
return(
<div>
<Tom gifts={this.callback}></Tom>
<hr/>
<Jerry lw={this.state.gift}></Jerry>
</div>
)
}
}
class Tom extends Component{
state={
gift:'滑板+溜冰鞋'
}
songli=()=>{
this.props.gifts(this.state.gift)
}
render(){
return(
<div>
<h1>Tom</h1>
<button onClick={this.songli}>给Jerry送礼</button>
</div>
)
}
}
class Jerry extends Component{
render(){
return(
<div>
<h1>Jerry</h1>
<h2>收到Tom给我的礼物了:{this.props.lw}</h2>
</div>
)
}
}
export default Parent3
组件之间的传值就完结了~忘了随时可查阅😊
组件生命周期
常用的三个:
- 创建时:componentDidMount(): 发Ajax请求,DOM操作
- 更新时:componentDidUpdate(): 接收Ajax请求,更新DOM操作
- 卸载时:componentWillUnmount(): 在组件卸载及销毁之前直接调用,销毁操作
额外两个:
- constructor():构造方法
- render():数据渲染时执行
演示示例测试
执行顺序constructor()–>render()---->componentDidMount()
更新执行:componentDidUpdate()并且会进行先渲染render()再更新
卸载此处用子组件验证,销毁子组件时执行
/**
* 创建时:componentDidMount(): 发Ajax请求,DOM操作
* 更新时:componentDidUpdate(): 接收Ajax请求,更新DOM操作
* 卸载时:componentWillUnmount(): 在组件卸载及销毁之前直接调用,销毁操作。
*/
import React, { Component } from "react";
class MyLife extends Component{
state={
num:1
}
constructor(){
console.log("1....构造方法");
super();
}
update=()=>{
this.setState({
num:this.state.num+1
})
}
render(){ //数据渲染时执行
console.log("2.....render进行渲染");
return(
<div>
<h1>组件生命周期{this.state.num}</h1>
<button onClick={this.update}>更新/攻击</button>
{this.state.num>3 ? <span>英雄噶了</span>:<Hero life={this.state.num}></Hero>}
</div>
)
}
componentDidMount(){
console.log("3.....组件挂载");
}
componentDidUpdate(){ //属性发生更新或者state发生更新触发
console.log(".....组件更新");
}
}
//子组件用于测试componentWillUnmount()卸载触发
class Hero extends Component{
componentWillUnmount(){ //卸载触发
console.log("....组件卸载");
}
render(){
return <h3>英雄被攻击次数:{this.props.life}</h3>
}
}
export default MyLife
路由
安装
npm install react-router-dom
引入
import {BrowserRouter as Router,Route,Link,Routes}from 'react-router-dom'
使用示例
- 语法:
<Link to="路径">描述</Link>
<Routes><Route path="路径" element={<组件名 />}></Route></Routes>
import React,{Component} from 'react'
import {BrowserRouter as Router,Route,Link,Routes}from 'react-router-dom' //(npm install react-router-dom)
const Main=()=><h3>我是首页哦</h3>
const Login=()=>(
<div>
<p>我是登录页面</p>
<input type='text' />
<button>登录</button>
</div>
)
const App=()=>(
<Router>
<h1>路由测试</h1>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/login">去登录</Link></li>
<li><Link to="/register">注册</Link></li>
</ul>
<Routes>
<Route path="/login" element={<Login/>}></Route>
<Route path="/" element={<Main/>}></Route>
</Routes>
</Router>
)
export default App
在index.js入口文件导入使用即可
子路由
只需要在路由中返回一个子路由即可
示例
const Main=()=>{
return (
<div>
<h3>我是首页哦</h3>
<ul>
<li><Link to="/register">注册</Link></li>
</ul>
<Routes>
<Route path="/register" exact element={<Register />} />
</Routes>
</div>
)
}
const Register=()=>(
<div>
<p>我是注册页面</p>
<input type='text' />
<button>注册</button>
</div>
)
const App=()=>(
<Router>
<h1>路由测试</h1>
<ul>
<li><Link to="/main">首页</Link></li>
</ul>
<Routes>
<Route path="/main" element={<Main/>}></Route>
</Routes>
</Router>
)
export default App
和路由一样记得引入…
发Ajax请求(使用axios)
安装
npm install axios
导入
import axios from 'axios' //导入axios(npm install axios
使用示例
此处用接口首页轮播图:https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata进行测试
最终响应到数据并赋值给info,循环显示在网页中
import React, { Component } from 'react'
import axios from 'axios' //导入axios(npm install axios)
class Apps extends Component{
state={
info:[]
}
handle=async ()=>{
let url="https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata"
let ret=await axios.get(url);
this.setState({
info:ret.data.message
})
}
render(){
return(
<div>
<h3>测试Axios请求</h3>
<button onClick={this.handle}>发Ajax请求</button>
{
this.state.info.map((item)=>{
return(
<p key={item.goods_id}>
<span>{item.goods_id}</span>
<img width="100px" src={item.image_src} />
</p>
)
})
}
</div>
)
}
}
export default Apps
完结撒花🌼~