创建React项目
第一种方式
npm i -g create-react-app
//your-project-name 项目名称
create-react-app your-project-name
第二种方式
//your-project-name 项目名称
npx creat-react-app your-project-name
React页面渲染
步骤
1.导入包
2.创建react元素
3.渲染元素到某个dom上
React内置了JSX
1.jsx必须要有一个根节点
2.属性名不能用js中的关键字,例如class,for
//class类 写为className
<div className="App-header"></div>
3.单标签要闭合
4.换行建议使用()包裹
5.老版本(16.8)之前,先引入react才能使用jsx
jsx-嵌入表达式
<div>{}<div>
{}中可以写:
1.表达式
2.其他的jsx表达式
3.注释
不可以写:
1.对象
2.js语句 if/switch/变量申明
jsx条件渲染
if/else
三元运算符
逻辑与运算符
switch case
必须要有一个根节点
import React from 'react';
import ReactDOM from 'react-dom/client';
function App1() {
// const num = Math.random()
const flag = true
const fn = () => {
if(flag){
return <p>成功</p>
}else{
return <p>失败</p>
}
}
const skills = [
{id:1,name:'html'},
{id:2,name:'css'},
{id:3,name:'js'}
]
// const list = [
// <ol>技能{skills[0].id}:{skills[0].name}</ol>,
// <ol>技能{skills[1].id}:{skills[1].name}</ol>,
// <ol>技能{skills[2].id}:{skills[2].name}</ol>
// ]
// const list = skills.map(item => {
// return <ol key={item.id}>技能{item.id}:{item.name}</ol>
// })
const list = skills.map(item => <ol key={item.id}>技能{item.id}:{item.name}</ol>
)
return (
<div className="App">
{list}
{fn}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
//<React.StrictMode> 严格模式
root.render(
<App1></App1>
);
jsx中的样式
//style
<div style={{position:'absolute',left:'10px'}} ></div>
//className
<div className = "mystyle"></div>
<style>
.mystyle{
position:'absolute',left:'10px'
}
</style>
JSX中使用本地图片
import logo from './logo.svg';
<img src={logo} className="App-logo" alt="logo" />
React组件
组件类型
1.基础组件
2.业务组件
3.区块组件
4.页面组件
React创建组件的两种方式
1.函数式组件(js是函数或箭头函数)
约定1.函数首字母大写
约定2.必须有返回值
const Com1 = ()=> {
return <div>函数组件</div>
}
2.类组件
注意:
1.类名必须以大写字母开头
2.render必须要有返回值
class Com2 extends React.Component {
render () {
return <div>类组件</div>
}
}
React有状态组件和无状态组件
状态:是用来描述事物在 某一时刻的形态 的 数据,一般称为state
状态的特点:状态能被改变,改变之后视图会对应的变化
有状态组件
能够定义state的组件,类组件就是有状态的组件
创建state第一种方式:
import React from 'react';
import ReactDOM from 'react-dom/client';
// 类组件
class Com2 extends React.Component {
state = {
num:100,
obj:{
name:'小花'
}
}
render () {
const { num, msg, obj } = this.state
return (
<div>
<p>num:{num}</p>
<p>msd:{msg}</p>
<p>obj的名字:{obj.name}</p>
</div>
)
}
}
创建state第二种方式:
import React from 'react';
import ReactDOM from 'react-dom/client';
// 类组件
class Com2 extends React.Component {
constructor (){
super()
this.state ={
num:1,
msg:'状态信息',
obj:{
name:'小花'
}
}
}
render () {
const { num, msg, obj } = this.state
return (
<div>
<p>num:{num}</p>
<p>msd:{msg}</p>
<p>obj的名字:{obj.name}</p>
</div>
)
}
}
无状态组件
不能定义state的组件,函数组件又叫无状态组件
应用场景:
1.组件本身不需要状态,例如渲染一段固定内容
2.组件本身没有状态,可以从外部传入
React中事件绑定
//语法
<元素 事件名1={ 事件处理函数1 } 事件名2={ 事件处理函数2 }>
class Com2 extends React.Component {
onClick () {
console.log('修改状态')
}
render () {
const { num, msg, obj } = this.state
return (
<div>
<button onClick={this.hClick()}>修改状态</button>
//上面一句代码 等价下一句代码
<button onClick={undefined}>修改状态</button>
</div>
)
}
}
注意:
1.React事件名采用驼峰命名法
2.在类中补充方法
3.this.fn不要加括号
事件对象
class Com2 extends React.Component {
hClick (e) {
//阻止默认行为
e.preventDefault()
//阻止冒泡行为
console.log('修改状态')
}
render () {
return (
<div>
<button onClick={this.hClick}>修改状态</button>
</div>
)
}
}
事件中this的指向
class Com2 extends React.Component {
hClick( e) {
console.log(this) //undefined
}
render () {
console.log(this) //
return (
<div>
<button onClick={this.hClick}>修改状态</button>
</div>
)
}
}
class内部启用了严格模式
render方法指向当前react组件
解决React事件处理程序中this指向问题主要有三种方式:
1.在外层补充箭头函数
2.Function.prototype.bind()
3.class的实例方法(推荐)
{/* 在外层补充箭头函数 */}
<button onClick={()=>{this.h2()}}>点我-箭头函数</button>
{/* bind */}
<button onClick={this.h3.bind(this)}>点我-bind</button>
{/* 实例方法 */}
<button onClick={this.h4}>点我-bind</button>
react 核心理念状态不可变
不能直接修改state改变视图,需要通过setState()
修改状态
class Com2 extends React.Component {
constructor (){
super()
this.state ={
num:1
}
}
hClick = () => {
this.setState({
num: this.state.num+1
})
}
render () {
const { num } = this.state
return (
<div>
<p>num:{num}</p>
<button onClick={this.hClick}>修改状态</button>
</div>
)
}
}
非受控组件-ref
借助 ref,使用原生DOM的方式来获取表单元素的值。使用步骤如下:
1.导入方法: import { createRef } from 'react';
2.调用createRef方法创建引用, 假设名为refDom , const refDom = createRef()
3.refDom设置给表单元素的ref
属性 ,<input ref={refDom} >
4.通过refDom.current.value
来获取值,
//class组件
class Com2 extends React.Component {
refDom = createRef()
constructor (){
super()
this.state ={
num:1
}
}
fn(){
console.log('点击',this.refDom.value)
}
render () {
return (
<div>
<input ref={this.refDom} type="text"></input>
<button onClick={()=>{this.fn()}}>点击按钮</button>
</div>
)
}
}
// 函数组件
const Com1 = ()=> {
const refDom = createRef()
const fn = () => {
console.log('点击',refDom.current.value)
}
return (<div>
函数组件
<input type="text" ref={refDom} />
<button onClick={fn}>点击按钮</button>
</div>)
}
受控组件
使用受控组件的方式获取表单的值
正常情况下,表单元素input是可用任意输入内容,可用理解为input自己维护它的状态(value)
受控组件的思路:
1.在state中定义状态
2.将state中的状态与表单元素的value绑定在一起,进而通过state中的状态来控制表单元素
//class组件
class Com2 extends React.Component {
refDom = createRef()
constructor (){
super()
this.state ={
msg:''
}
}
fn2 = (e)=>{
this.setState({
msg:e.target.value
})
}
render () {
const { msg } = this.state
return (
<div>
<input onChange={this.fn2} type="text" value={this.state.msg}></input>
</div>
)
}
}
React组件
组件拆分到文件
1.创建组件
//Header.js
import React, { Component } from 'react'
export default class Header extends Component {
render() {
return (
<div>
这是一个组件
</div>
)
}
}
2.使用组件
import Header from './Header';
//部分代码
return (
<div className="App">
<Header />
</div>
);
React组件通讯的三种方式
1.父子组件之间
父传子 props
父组件-传入数据
<子组件 自定义属性1={值1} 自定义属性1={值2}>
export default class Parents extends Component {
render() {
return (
<div>
父组件
<Son age={18} name="小花" />
</div>
)
}
}
函数式子组件接受数据:props
function Son(props){
return <div>子组件</div>
}
Class子组件接受数据:this.props
//类组件部分代码
render() {
const { age, name } = this.props
return (
return <div>子组件</div>
)
}
子传父 props
利用回调函数,父组件提供回调,子组件调用,将传递的数据作为回调函数的参数。
//父组件
export default class Parents extends Component {
state = {
num:1
}
f = (num) =>{
this.setState({num})
}
render() {
return (
<div>
{this.state.num}
<Son f={this.f} />
</div>
)
}
}
Class子组件接受数据:this.props
//子组件部分代码
hClick = () =>{
this.props.f(1)
}
render() {
const { age, name } = this.props
return (
return (<div>
<button onClick={this.hClick}>把1传给父组件</button>
</div>)
)
}
2.兄弟组件之间
状态提升,定义在子组件状态,提升到父组件中,以父组件作为桥梁,让兄弟之间进行通讯。
//父组件
export default class Parents extends Component {
state = {
num:1
}
f = (num) =>{
this.setState({num})
}
render() {
return (
<div>
{this.state.num}
<Son1 f={this.f} />
<Son2 num={this.state.num} />
</div>
)
}
}
//子组件部分代码
hClick = () =>{
this.props.f(1)
}
render() {
const { age, name } = this.props
return (
return (<div>
<button onClick={this.hClick}>把1传给父组件</button>
</div>)
)
}
//son1子组件部分代码
hClick = () =>{
this.props.f(1)
}
render() {
const { age, name } = this.props
return (
return (<div>
<button onClick={this.hClick}>把1通过父组件传给兄弟组件</button>
</div>)
)
}
//son2子组件部分代码
render() {
return (
return (<div>
{this.props.num}
</div>)
)
}
3.跨组件层级Context()
import { createContext } form 'react'
const { Provider, Consumer } = createContext()
Provider包裹根组件
return (
<div>
// store={store} 需要传的值
<Provider store={store}>
<App></App>
</Provider>
</div>
)
任意后代组件,可使用Consumer
组件包裹整个组件
render(){
return (
<Consumer>
{
(data) => {
return <div>这里是组件的内容,data是传过来的数据</div>
}
}
</Consumer>
)
}
React中 props基本使用
使用props语法能够将数据从父组件传到子组件
props注意事项:
1.可以传递任意数据(包括函数,jsx)
2.props是只读属性(不可以修改)
数据是谁的谁去改
3.单向数据流 自上而下
props中的children属性 (传结构)
只要组件有子节点,props就有该属性
<Girl age={18} name="小花">
<h5>h5标签</h5>
</Girl>
//props.children
//Girl 组件
function Girl(props){
return <div>{props.children}</div>
//等价 <div><h5>h5标签</h5></div>
}
//可以传结构
propstype 校验
improt PropTypes from 'prop-types'
// App为组件的名字
App.propsTypes = {
pagesize:PropTypes.number
}
props给组件设置默认值 的两种方式
1.defaultProps
//组件App部分代码
// App为组件的名字
App.propsTypes = {
pagesize:PropTypes.number
}
2.结构赋值的默认值
const {pagesize=10} = this.props
//组件App部分代码
//设置默认值
APP.defaultProps = {
pagesize:10
}
React生命周期
执行时机:组件创建时(页面加载时)
生命周期
挂载时:
constructor()---->render()---->ComponentDidMount()
1. constructor()
创建组件时最先执行
作用:1.初始化state 2.创建Ref
2. render()
每次组件渲染都会触发
作用:渲染ui
3.ComponentDidMount()
组件挂载(完成DOM渲染)后
作用:1.发送网络请求 2.DOM操作
更新时
render()----> ComponentDidUpdate()
三种情况下可以导致更新 new props
(父组件传入的数据发生改变) 、 this.setState()
、this.forceUpdate()
卸载时
ComponentWillUnmount()
可以清除定时器 移除事件 比如监听器
setState
this.setState(
{ link: 'http://www.chao99.top' },
() => console.log('这是回调函数')
)
setState三个特点
- 可以表现为异步
setState调用之后,并不会立即去修改state的值,也不会立即更新DOM - 多次调用会合并,统一后触发一次
render()
- 使用不当会造成死循环 在
render()
,ComponentDidUpdate()
中调用setState()
会导致死循环
setState第二个参数是回调函数
该函数会在setState函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成
React hooks
hooks 是一些函数 可以让在函数组件中“钩入”React state及生命周期的新特性
hooks只能在函数组件使用
hooks和现有代码可以同时工资,可以渐进式地使用
hooks带来了更强大的逻辑复用
useState
修改函数组件状态
格式一:
const res = useState(100)
const [count,setCount] = res
格式二:
const [content,setContent] = useState(()=>{
return 'abc'
})
useState函数中:可以计算、localStorage拿值
注意:
1.只能出现在函数组件内部
2.useState不能使用if或for中,如果存在无法知道调用的是哪个hooks
userffect 理解副作用
函数式组件中
主作用:根据数据渲染ui
副作用:数据请求,手动修改DOM、localstorage操作等
userEffect挂载和更新时会执行
userEffect(()=>{
//事件绑定,请求数据
},[])
//n改变执行
userEffect(()=>{
},[n])
// 参数为空,只执行一次
userEffect(()=>{
},[])
n变化执行(依赖项变),依赖项可以多个
副作用函数 返回值
返回值可以清理副作用
清理函数会在组件卸载以及下一次副作用函数调用前执行
useEffect(()=>{
setInterval(()=>{
setCount((count)=>count - 1)
},1000)
return ()=>{
console.log('清理副作用')
}
},[])
useEffect可以模拟函数钩子
自定Hooks
逻辑复用
自定义Hooks 名字用use开头
只能在函数组件或自定义hooks中调用
useRef
使用场景:在React中进行DOM操作时,用来获取DOM
作用:
1.返回一个带有current属性的可变对象,通过该对象可以进行DOM操作
2.多次渲染中共享数据
import { useEffect, useRef, useState } from 'react'
const refTimerId = useRef(null)
//部分代码
const hClick = () =>{console.log(refTxt.current.value)}
<input ref={refTxt} />
<button onClick={this.hClick}>点击获取input中的值</button>
useContext 全局状态
跨组件通讯
// index.js 根组件
import React, { useState,createContext } from 'react'
import Father from './Father'
export const Context = createContext()
export default function Index() {
const [color,setColor] = useState('red')
return (
<Context.Provider value={color}>
<div style={{border:'1px solid #ccc',margin:40}} >
根组件:
color:{color}
<button onClick={()=>{
setColor('green')
}}>
改成green
</button>
<Father></Father>
</div>
</Context.Provider>
)
}
//Father组件
import React from 'react'
import Son from './Son'
export default function Father() {
return (
<div style={{border:'1px solid #ccc',margin:10}}>
父组件
<Son></Son>
</div>
)
}
import React,{useContext} from 'react'
import {Context} from './index'
function Son() {
const res = useContext(Context)
return (
<div style={{border:'1px solid #ccc',margin:10}}>
子组件:color:{res}
</div>
)
}
export default Son
Redux
多组件共享数据
安装redux
npm i redux
redux核心概念:
1.store
2.action
3.reducer
react-redux
npm i react-redux
reducer分离
combineReducers 合并reducer
纯函数
相同的输入总是得到相同的结果
reducer也是纯函数
拓展优化 action-creator
优化 action-type
redux-中间件-redux-thunk
支持dispatch函数格式
npm i redux-thunk
redux-中间件-redux-logger
npm i redux-logger
redux调试工具
未完,持续更新…