创建项目
方法一:先全局安装npm i create-react-app -g
再create-react-app myreact
方法二:npx create-react-app myreact
function组件
import React from 'react'
import ReactDom from 'react-dom'
var name = 'bzw';
/*react组件都是函数*/
/*
结构中变量都用 {} 包起来
组件中根元素 只能由一个根标签 但是可以是一个空标签
结构中不能有关键字 class => calssName for => htmlFor
结构中不能直接把对象 作为儿子; 若是数组直接把拼接的结果扔到了结果中
循环结构一般使用map
*/
function mymap(ary){
let t = [];
for(var i = 0;i < ary.length; i++){
t.push(<li key={i+10}>{ary[i]}</li>)
}
return t;
}
function List(){
var obj = {a:12,b:13};
var h1 = <h1>哈哈</h1>;
var ary = [1,2,3];
// var ary2 = [<i>1</i>,<i>2</i>,<i>3</i>]
return <ul className="box">
{
ary.map(item=>{
return <li key={item}>{item}</li>
})
}
{mymap(ary)}
<li>{name}</li>
<li>{obj.a}</li>
<li>{h1}</li>
<li>{JSON.stringify(obj)}</li>
<li>{ary}</li>
{/* <li>{ary2}</li> */}
<li><input type="checkbox" name="" id="qqq"/><label htmlFor="qqq">9999</label>
</li>
</ul>
}
ReactDom.render(<>
<h2>我的react</h2>
{/* 在react的结构模板中,想要使用变量 需要用 {变量和表达式} 包起来*/}
{name}
<List></List>
</>,document.querySelector('#root')
)
import React from 'react';
import ReactDom from 'react-dom';
// 组件首字母必须大写
//用function一般称为静态组件或者函数式组件
function App666(props) {
console.log(arguments);
return (<div>
<p style={{color:props.style}}>123</p>
</div>)
}
function H1() {
return <h1>家哈哈</h1>
}
// 凡是在组件上使用的行内属性都是自定义属性
// 在原生html上标签使用的都是react规定的
ReactDom.render(<>
<App666 className="box1" id={666} qqq={622} style="red"/>
<H1/>
</>,document.getElementById("root"))
class组件
import React from 'react';
import ReactDom from 'react-dom';
console.log(React.Component);
// 在class组件中,结构是通过rander函数返回结果决定的
class App extends React.Component{
// 创造一个APP类,继承React.Component这个类
// constructor(props){ //接收值
// // 在class声明类的时候,写了constructor 必写super() => 相当于call继承
// super(props)
// }
render(){
console.log(this.props);
// this.props中的属性只读,不能改
return <div>啦啦啦</div>
}
}
ReactDom.render(<App className123='box'/>,document.getElementById("root"))
状态和属性
import React from 'react';
import ReactDom from 'react-dom';
// react组件只有两个数据源: 一个是属性props; 另一个state
class App extends React.Component{
constructor(){ //接收值
super()
this.state = {
// 这里放当前组件的私有属性
name:"zhangsan",
time:new Date().toLocaleString(),
}
}
// 想让视图更新: react规定需要调用setState这个方法,也就是让render函数执行
// 在render中 不能写setState 这个方法执行,会触发死循环
componentDidMount(){
// 当组件的DOM渲染完成后 会触发这个函数
setInterval(() =>{
this.setState({
// 也就是主动触发双向数据绑定
time:new Date().toLocaleString()
})
})
}
render(){
let {className} = this.props;
let {name, time} = this.state;
return <div className={className}>
{name}
<h2>{time}</h2>
</div>
}
}
ReactDom.render(<App className='box'/>,document.getElementById("root"))
事件
import React from 'react';
import ReactDom from 'react-dom';
// 属性:从外部传过来的 状态(state):自己定义的
// 类组件
class App extends React.Component{
// constructor(){
// super()
// this.state = {
// count:100
// }
// }
state = {
count: 100,
aa:20
}
add(n,e){
console.log(e.nativeEvent,e.target);
// console.log("+")
// console.log(this);
this.setState({
count: this.state.count+n
})
}
minus(e,n){
console.log(e);
console.log(n);
// console.log("-");
// setStste更新数据 大部分 是异步操作
// 在 原生事件绑定中 或者 定时器 中总是同步的
this.setState({
count: this.state.count-n,
aa:this.state.aa-1
},function () {
// 数据更新之后触发
// console.log(this.state.count);
})
}
minus2=(e)=>{
// console.log(this);
console.log(e);
this.setState({
count: this.state.count+1
})
}
over(){
// console.log("over");
}
componentDidMount(){
}
render(){
let {count} = this.state
return <div className=''>
{/* on+事件名 事件名遵循 驼峰命名 合成时间(就是原生事件) */}
<button onClick={this.add.bind(this)}>+</button>
{/* bind的返回结果给了onClick,这里一旦bind之后this就改不了了 (不能用call,call直接让函数执行,返回了执行结果;bind返回的是函数体吧)*/}
<button onClick={this.add.bind(this,10)}>+10</button>
<button onClick={this.add.bind(this,100)}>+100</button>
<button onClick={(e)=>{this.minus(e,10)}}>-10</button>
{/* 把箭头函数给了onClick ,箭头函数的作用域就是上级作用域的this,上级作用域就是render*/}
<button onClick={this.minus2}>---</button>
<h2 onMouseOver={this.over}> {count} {this.state.aa}</h2>
</div>
}
}
ReactDom.render(<App/>,document.getElementById("root"))
useState
import React from 'react';
import ReactDom from 'react-dom';
import { useState } from 'react';
// function组件(函数是组件 静态组件)
// 更新比较少使用函数是组件 多的话用类组件
/* function App (){
let [count,setCount] = useState(10);
let [name,setName] = useState("张三")
function add(){
let t = count + 100
setCount(t) //更新count 并且触发视图更新 {setState({count:t})}
// console.log(count);
}
return <div>
<button onClick={add}>+</button>
<button onClick={()=>{setName("啦啦啦啦")}}>+</button>
{count}
{name}
</div>
} */
function App (){
let [state,setState] = useState({
count:100,
name:"zhang"
})
function add(){
let t = state.count+10
let obj= {
...state,
count:t
}
setState(obj)
}
function miuns(){
let t = state.count-10
setState({
...state,
count:t
})
}
function setName11(){
setState({
...state,
name:"哈哈哈"
})
}
return <div>
<button onClick={add}>+</button>
<button onClick={miuns}>---</button>
<button onClick={setName11}>+</button>
{state.count}
{state.name}
</div>
}
ReactDom.render(<App/>,document.getElementById("root"))
子父组件
import React, { Component } from 'react';
import ReactDom from 'react-dom';
// import propTypes from "prop-types" //用来处理传进来的数据的情况
import qqq from "prop-types"
// 子传父:通过事件参数传递
// 父传子: props
// 限制传进来的数据的情况
class Button extends Component{
static propTypes = {
// className:qqq.string , //className必须是个字符串 规定单个数据类型
className: qqq.oneOfType([ //规定多个数据类型
qqq.string,
qqq.number,
]).isRequired, //必传
}
state={
name:"woshizizujian"
}
click=()=>{
this.props.onClick123 && this.props.onClick123()
this.props.onChangeName && this.props.onChangeName(this.state.name)
}
// 给默认值的
// static defaultProps = {
// className: 'qqqqqqqq'
// };
render(){
let {className="qqq",onClick123,children="hahahh",} = this.props //children:字符串,数组,对象(单个节点(标签)虚拟DOM)
// return <button className={className} onClick={onClick123}>{children}</button>
return <button className={className} onClick={this.click}>{children}</button>
}
}
class App extends React.Component{
constructor(){
super()
this.state = {
name:"zhangsan",
className:"box"
}
}
fn=()=>{
// console.log(e);
console.log(666);
this.setState({
name:"zhufengpeixun"
})
}
qqq=(name)=>{
this.setState({
name:name
})
}
render(){
return <div className=''>
<Button className={this.state.className}><i>222</i></Button>
<Button onClick123={this.fn}/>{this.state.name}
<Button onChangeName={this.qqq}/>
</div>
}
}
ReactDom.render(<App/>,document.getElementById("root"))
ref
import React from 'react';
import ReactDom from 'react-dom';
/*
获取DOM元素或组件
ref不能获取函数是组件
ref="xxx" this.refs.zzz 将要废弃
ref = {(el)=>{this.xxx = el}} this.xxx
this.xxx = React.createRef() this.xxx.current */
class App extends React.Component{
constructor(){
super()
this.www = React.createRef()
this.state = {
}
}
fn=()=>{
console.log(this.refs.aaa);
console.log(this.qqq);
console.log(this.www.current);
}
render(){
return <div className=''>
<button onClick={this.fn}>按钮</button>
<p className="qqq" ref="aaa">6666</p>
<p className="qqq" ref={(el)=>{this.qqq=el}}>6666</p>
<p ref={this.www}>6666</p>
</div>
}
}
ReactDom.render(<App/>,document.getElementById("root"))
钩子函数
import React from 'react';
import ReactDom from 'react-dom';
class Page1 extends React.Component{
componentWillUnmount(){
console.log("page1销毁");
}
render(){
return <h1>page1</h1>
}
}
class Page2 extends React.Component{
componentWillUnmount(){
console.log("page2销毁");
}
render(){
return <h1>page2</h1>
}
}
// 钩子函数:某个阶段执行某个对应的函数
class App extends React.Component{
constructor(){ //第一个钩子函数:初始化
super()
this.state = {
name:"4568",
type:"page1"
}
}
/* static getDerivedStateFromProps(props,state){
// 主要目的:把props中的属性合并到state(实际上是把这个函数返回的东西合并到state中)
// props:父组件传来的数据
// state:就是自己的数据
// 这个函数必须返回一个对象
console.log(props,state);
return {
...props,
aaa:123456
}
}
componentWillMount(){
// 类似于beforemount
// DOM渲染完成之前,可以同步更改 将要被废弃的一个钩子函数
this.state.name = 9999
console.log();
}
componentDidMount(){
// DOM渲染完成后执行的钩子函数
// 操作DOM(echerts 百度地图)
// 发送ajax请求
}
// componentWillReceiveProps(newProps){
// // 当父组件传进来的数据更新时触发 将要被废弃的一个钩子函数
// }
shouldComponentUpdate(newProps,newState){
// 这个钩子函数可以用来控制组件是否更新
// 可以用来提升组件的渲染效率,是用来优化的钩子函数
return false
}
componentDidUpdate(prevProps,prevState){
// DOM更新完成后触发
}
componentWillUnmount(){
// 组件销毁前
} */
// PureComponent 唇组件 写这个就不用写shouldComponentUpdate()了
/* 特点:会自动进行新老props校验,也就是会自动执行shouldComponentUpdate
只会进行一层校验
*/
render(){
console.log(6666);
let {type} = this.state
console.log(this.state);
return <div className=''>
{this.state.name}
<button onClick={()=>{this.setState({type:"page1"})}}>page1</button>
<button onClick={()=>{this.setState({type:"page2"})}}>page25</button>
{
type == "page1"?
<Page1/>:
<Page2/>
}
</div>
}
}
ReactDom.render(<App/>,document.getElementById("root"))
useEffect
import React,{useEffect,useState} from 'react';
import ReactDom from 'react-dom';
// state 是为了让函数式组件使用 setState
// useEffect 是为了让函数式组件使用钩子函数
function App() {
let [count,setCount] = useState(100)
let [name,setName] = useState("珠峰")
useEffect(()=>{
//类似于componentDidMount和componentDidUpdate的结合体
// 可以通过第二个人参数来决定啥时候执行
console.log(count);
// console.log(name);
},[count])
useEffect(()=>{
// 个数不限制 比如想在name发生改变时触发
console.log(name);
// console.log(name);
},[name])
useEffect(()=>{
// 传参为空数组,表示只在初次加载时使用
},[])
return <div>
hello
<button onClick={setCount.bind(null,count+1)}>改变</button>
<h1>{count}</h1>
<button onClick={()=>{setName("珠峰培训")}}>改变</button>
<h1>{name}</h1>
</div>
}
ReactDom.render(<App/>,document.getElementById("root"))
router
import React from 'react';
import ReactDom from 'react-dom';
import {BrowserRouter, HashRouter, Link, NavLink, Route, Switch, Redirect} from "react-router-dom"
// BrowserRouter 利用的是 H5 的history Api; 对比vue就是history 利用的是popState
// HashRouter 利用的是 hashChange; 对比vue是hash模式
// 项目中 我们需要使用其中一个把根组件抱起来
//Link 相当于 vue 的 router-link 用来跳转对应路径(to属性跟的值)
// NavLink 用法 = Link 比Link多一个类名
// Route 相当于 vue 的 router-view 用来展示对应的哪个组件
// Switch 用这个组件把用到的route抱起来 可以避免react每一个route都去匹配的情形
// Redirect 重定向
// 在react 我们可以使用search 或者 params的方式进行参数传递
// 若是search 通过loaction.search 或者this.props.location.search
// 若是params 我们需要在编写Route组件的时候 /xxx/:属性名, 调用的时候 通过this.props.match.params获取 参数少
// react中路由懒加载 npm i react-loadable
// import Home from "./component/home"
// import User from "./component/uaer"
import Loadable from 'react-loadable';
const Home = Loadable({
loader: () => import(/*webpackChunkName:"home"*/'./component/home'),
loading: ()=><h3>正在加载</h3>,
});
const User = Loadable({
loader: () => import(/*webpackChunkName:"user"*/'./component/uaer'),
loading: ()=><h3>正在加载</h3>,
});
let Temp = ()=><h1>啦啦啦</h1>
class App extends React.Component{
constructor(){
super()
this.state = {
}
}
render(){
return <div className=''>
<Link to="/home/666">首页</Link>
<Link to="/user">用户</Link>
<NavLink to="/home/777">首页</NavLink>
<NavLink to="/user?qqq=123&aaa=456">用户</NavLink>
<Switch>
{/* <Route path="/" exact component={Temp}>哈哈哈哈</Route> */}
{/* exact是一个精确匹配 只有路径 与 path的值 完全相等 才可*/}
<Redirect path="/" exact to="/home"></Redirect>
{/* 当前路径如果是/ 则重定到/home */}
<Route path="/home/:qqq" component={Home}></Route>
<Route path="/user" component={User}></Route>
<Route path="/*">404</Route>
</Switch>
</div>
}
}
ReactDom.render(
<HashRouter>
<App/>
</HashRouter>,document.getElementById("root"))
// 传参:方法传参、隐形传参、路径参数