近日学习react 17.0.2版本的笔记,不多讲了上教程加代码
新建项目
- npm install -g create-react-app 全局安装
- create-react-app my-app 新建并对react项目进行命名(注:项目名称不能有大写)
- cd my-app
- num run start
PS:以上是webpack创建react项目方式 本人也只用过webpack其他方式暂时先不做。
关于React
英文官网: https://reactjs.org/
中文官网: https://react.docschina.org/
其优点
1.声明式编码
2.组件化编码
3.React Native 编写原生应用
4.高效(优秀的Diffing算法)
还是不讲废话了 直接来开始react的使用
React JSX
学习react的时候这个是必看的
-
JSX全称: JavaScript XML
-
react定义的一种类似于XML的JS扩展语法: JS + XML本质是
React.createElement方法的语法糖
-
作用: 用来简化创建虚拟DOM
-
写法:var ele =
Hello JSX!
注意1:它不是字符串, 也不是HTML/XML标签
注意2:它最终产生的就是一个JS对象
-
标签名任意: HTML标签或其它标签
-
标签属性任意: HTML标签属性或其它
-
基本语法规则
遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含 -
babel.js的作用
浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
只要用了JSX,都要加上type=“text/babel”, 声明需要babel来处理
React面向组件编程
注意点
-
组件名必须首字母大写
-
虚拟DOM元素只能有一个根元素
-
虚拟DOM元素必须有结束标签
组件三大核心属性1: state
import React,{Component} from "react";
export default class StateTest extends Component{
constructor(props){
super(props)
this.state={
my:'5555'
}
}
render(){
const abc = this.state //state的
console.log(abc); //{'my:5555'}
return(
<div>我是state组件</div>
)
}
}
来看一下输出结果
对于state的理解
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
注意:组件中render方法中的this为组件实例对象
组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
状态数据,不能直接修改或更新
组件三大核心属性2: props
import React,{Component} from "react";
export default class Props extends Component{
constructor(props){
super(props)
console.log(props)
}
render(){
return(
<div>
真的挺牛逼的
</div>
)
}
}
组件三大核心属性3: refs与事件处理
- 字符串形式的ref
<input ref="input1"/>
- 回调形式的ref
<input ref={(c)=>{this.input1 = c}}
- createRef创建ref容器
import React, { Component } from "react";
export default class InputRef extends Component {
constructor(props) {
super(props)
this.inputdiv = React.createRef()
}
getvalue() {
console.log(this.inputdiv.current.value) //能获取input中的值
}
render() {
return (
<form>
<input type='text' ref={this.inputdiv}></input>
<button onClick={() => this.getvalue()}>获取</button>
</form>
)
}
}
-
事件处理
- 通过onXxx属性指定事件处理函数(注意大小写)
- React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
- React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
- 通过event.target得到发生事件的DOM元素对象
import React, { Component } from "react";
export default class Ref extends Component{
constructor(props){
super(props)
this.mydiv = React.createRef()
this.inputidv = React.createRef()
}
componentDidMount(){
console.log(this.mydiv.current)
}
render(){
return(
<div ref={this.mydiv}>
995
</div>
)
}
}
this.my.current能获取Dom
简单来做个小案例
- 父子组件之间的通信
首先是父传子之间的案例
父组件
// app.js
import React, { Component } from "react";
import News from './test';
export default class News extends React.Component {
render() {
return (
<News id='gcy' /> //id是传递的参数名 gcy是参数值
)
}
}
子组件 可以使用this.props接受父组件的传参
// index.jsx
import React, { Component } from "react";
export default class News extends Component {
console.log(this.props.id) //输出结果为gcy
render() {
return (
<div>News
<span>{this.props.id}</span>
</div>
)
}
}
来看看界面
子传父的案例
子组件 通过使用this.props.自己的事件名(‘参数’)
import React from 'react'
export default class Test extends React.Component {
constructor(props) {
super(props)
this.state = {
message: '你好啊'
}
}
dianji = () => {
this.setState({
message: '好的吧'
})
}
sends = () => {
this.props.OnMy('masssss'); // 注意这里通过this.props发送
}
render() {
return (
<div>
<p onClick={this.dianji.bind(this)}>{this.state.message}</p>
<h5 onClick={this.sends.bind(this)}>子传父</h5> //这里是子传父的事件
</div>
)
}
}
父组件
import React, { Component } from "react";
import Test from './test/index2'
export default class App extends React.Component {
my =(data)=>{
console.log(data) // 这里的data就是接收的值了
}
render() {
return (
<Test OnMy={this.my} /> //通过OnMy接收
)
}
}
看下输出结果
我来出一个比较连贯的题目,一个父组件和两个子组件,子组件1传递参数名id过去,id的值为1,父组件接收后再通过点击事件传递给子组件2,这里就不贴代码了,新手可以尝试下,做不出来可以私信我要代码或者思路。
- form表单,input以及textarea案例
from表单以及input
import React, { Component } from "react";
import './from.css'
export default class From extends Component {
constructor(props) {
super(props);
this.state = { value: '', value2: '' };
this.handleSubmit = this.handleSubmit.bind(this); //this指向问题
this.handleChangetewo = this.handleChangetewo.bind(this) //this指向问题
}
handleChange(event) {
this.setState({ value: event.target.value }); //event为Input中的值
}
handleChangetewo(event) {
this.setState({ value2: event.target.value }) //event为Input中的值
}
handleSubmit(event) {
alert('提交的名字: ' + this.state.value + '密码是' + this.state.value2);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}> //提交的点击事件
<label>
名字:
<textarea type="text" value={this.state.value} onChange={this.handleChange.bind(this)} />
密码:
<input type='password' value={this.state.value2} onChange={this.handleChangetewo} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
来看一下alert的结果
- select案例
import React, { Component } from "react";
export default class Select extends Component {
constructor(props) {
super(props)
this.state = {
data: [
'213', '555', '214', '你', '西瓜'
],
value: '213'
}
}
changevalue(event) {
this.setState({ value: event.target.value }) //value值为设置的值
}
handleSubmit(event) {
alert(this.state.value)
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<select value={this.state.data.value} onChange={this.changevalue.bind(this)}>
{
this.state.data.map((item, index) => {
return <option key={index}>{item}</option>
})
}
</select>
<input type="submit" value="提交" />
</form>
)
}
}
来看一下alert结果
生命周期函数
- 初始化阶段: 由ReactDOM.render()触发—初次渲染
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount()
- 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
来具体看下代码吧
componentDidMount() 初次渲染 可以设置定时器查看输出结果**
import React, { Component } from "react";
import Child1 from "./child";
import Child2 from "./child2";
export default class Parent extends Component {
constructor(props) {
super(props)
this.state = {
mes: ''
}
}
componentDidMount() {
this.timer = setInterval(() => {
console.log('初次渲染') //最好设置定时器
}, 1000)
}
MyEvent = (data) => {
this.setState({
mes: data
})
}
render() {
return (
<div>
<span>我是把把</span>
<Child1 onMyEvent={this.MyEvent} />
<Child2 mymes={this.state.mes} />
</div>
)
}
}
componentDidUpdate() 由组件内部this.setSate()或父组件重新render触发
import React, { Component } from "react";
import Child1 from "./child";
import Child2 from "./child2";
export default class Parent extends Component {
constructor(props) {
super(props)
this.state = {
mes: ''
}
}
componentDidUpdate() {
console.log('更新后')
//当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。
}
MyEvent = (data) => {
this.setState({
mes: data
})
}
render() {
return (
<div>
<span>我是把把</span>
<Child1 onMyEvent={this.MyEvent} />
<Child2 mymes={this.state.mes} />
</div>
)
}
}
通过点击这个按钮传给child2值
看一下输出结果
页面进行了render的重绘所以触发了componentDidUpdate()生命周期
componentWillUnmount() 用于一些收尾的工作 比如清除定时器
import React, { Component } from 'react';
import { Link } from 'react-router-dom'
export default class Home extends Component {
componentWillUnmount() {
console.log('我马上去shop家里');
}
render() {
return (
<div>你好我是home
<Link to='/shop'>我要去shop家里看望冯昕</Link>
</div>
)
}
}
点击link后
来看一下输出结果
这个时候home界面跳到了shop界面 完成了页面的卸载
React-router-dom
首先是最基本的安装
npm
npm install react-router-dom@6
yarn
yarn add react-router-dom@6
最基本的配置
在index.jsx中的基本配置
import React from "react";
import ReactDOM from "react-dom";
import Router from "./router";
import "./index";
ReactDOM.render(<Router />, document.getElementById("root"));
在router中index.jsx配置
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../test/home";
import Shop from "../test/shop";
export default function Router() {
return (
<BrowserRouter>
{/* 使用 Routes 替换 Switch */}
<Routes>
<Route path='/' element={<Home />} />
<Route path='/shop' element={<Shop />} />
</Routes>
</BrowserRouter>
);
}
这样路由最基本的配置就有了 url中 http://localhost:3000就是home界面 http://localhost:3000/shop就是shop界面了
嵌套路由
在router.jsx中这样配置
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../test/home";
import Shop from "../test/shop";
import Shui from "../test/shui";
import Hua from '../test/hua'
export default function Router() {
return (
<BrowserRouter>
{/* 使用 Routes 替换 Switch */}
<Routes>
<Route path='/' element={<Home />} />
<Route path='shop' element={<Shop />} > //需要用Router包裹子路由
<Route path='shui' element={<Shui />} />
<Route path='hua' element={<Hua />} />
</Route>
</Routes>
</BrowserRouter>
);
}
父路由中配置shop.jsx 切记使用Outlet 不然界面是渲染不出来的
import React, { Component } from 'react';
import { Outlet } from 'react-router-dom'
export default class Shop extends Component {
render() {
return (
<div>你好我是shop
<Outlet /> //需要Outlet在父路由中配置
</div>
)
}
}
路由的跳转
link跳转
现在有home路由以及shop路由,home.jsx中配置link跳转
import React, { Component } from 'react';
import { Link } from 'react-router-dom'
export default class Home extends Component {
componentWillUnmount() {
console.log('我马上去shop家里');
}
render() {
return (
<div>你好我是home
<Link to='/shop'>我要去shop家里</Link>
</div>
)
}
}
useNavigate跳转
注意:useNavigate不能使用在类组件中使用
import React from "react";
import { useNavigate } from "react-router-dom";
export default function Lei() {
const navigate = useNavigate();
const handleClickToHome = () => {
navigate("/shop");
};
return (
<div>
<h2>我是类</h2>
<button onClick={handleClickToHome}>去购物了</button>
</div>
);
}
路由的传参
- params传参
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../test/home";
import Shop from "../test/shop";
import Shui from "../test/shui";
import Hua from '../test/hua'
import Lei from "../test/lie";
import Shui1 from "../test/shui1";
import Me from "../test/Me";
import Our from "../test/our";
export default function Router() {
return (
<BrowserRouter>
{/* 使用 Routes 替换 Switch */}
<Routes>
<Route path='/' element={<Home />} />
<Route path='shop' element={<Shop />} >
<Route path='shui/:id' element={<Shui />} />
<Route path='hua' element={<Hua />} />
</Route>
<Route path='/lei' element={<Lei />}></Route>
<Route path='/me/:id' element={<Me />}></Route> //这里me是主角
<Route path='/our' element={<Our />}></Route>
</Routes>
</BrowserRouter>
);
}
跳转路由的配置
import React, { Component } from 'react';
import { Link } from "react-router-dom";
export default class Shui extends Component {
constructor(){
super()
this.state={
over:[{
id:1,
name:'小明'
},{
id:2,
name:'小绿'
}],
oo:55
}
}
render() {
console.log(this.props)
return (
<div>
{
this.state.over.map((item,index)=>{
return <p key={item.id}><Link to={{pathname:`/me/${this.state.oo}`}}> {item.name}</Link></p>
})
}
</div>
)
}
}
路由的接收配置
import React, { Component } from 'react';
import { useParams,useSearchParams } from "react-router-dom";
export default function Me() {
const par = useParams()
const pars = useSearchParams()
console.log(pars); //其实是个对象
console.log(par); //{id:'55'}
return (
<div>555ME</div>
)
}
看一下输出结果吧
这样就完成了params的传参了