React

react.js

react.js引入后可以使用

  • 创建虚拟dom
    React.createElement(type,props,children)
    • type 虚拟dom类型,可写入'h1'等标签类型
    • props 属性,当前标签可用属性接可
    • children 子元素,也就是需要写入的内容
      创建多个子元素,用jsx实现更好,但顶层元素只能有一个
js 复制代码
    React.createElement("header",{id: "title"},
          React.createElement("h1", null, "hello"),
          React.createElement("p", null, "nihao")
     )

虚拟dom

对象类型,console.log如下

优点:按需渲染性能好

reactDom

react-dom.js引入后可以使用

  • dom渲染
    ReactDOM.render(element, container, callback)
    element: 要渲染的内容
    container: 渲染内容的容器
    callback: 渲染后的回调函数,非必传

jsx

=js+xml,在js中使用xml语法

需要引入babel,引入后在script标签上用type='text/babel'指定

js 复制代码
    ReactDOM.render(
        <header id='title' style="{{color: 'red',...}}">
          <h1>...<h1>
          ...
        </header>
     )

class->className

style接收一个对象(第一个{}是插值的,第二个才是对象的)

插值表达式

注意不要加''会被识别为字符串

可以叠加js表达式(会返回一个值的,正则等),但不能用if,while,for等语句

js 复制代码
let text = document.querySelector('#text')
ReactDOM.render(
<div> { text.value }</div>
)

在函数里用jsx最好在return时用()包裹一下

注释需要写在插值{/* .注释内容... */}里再注释

布尔值、空和未定义都会直接被忽略,不能输出对象(直接报错),数组可以(会用空白替换,分割)

  • 列表渲染
    jsx不能写循环语句,但可以把页面元素放到数组里,再让jsx渲染数组
    在项目中需要给重复的元素增加key属性

react工程

createReactApp命令

npm i create-react-app

create-react-app my-app // my-app是自定义的工程文件夹名

如果报错可以尝试npx create-react-app my-app,npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装。

  • eject 不可逆的抛出配置

项目目录

index.js入口文件,会引入App.vue

App.vue全局根组件

大写组件小写标签

函数式组件

函数名称=组件名

函数返回值=组件渲染内容,需要返回一个reactElement

js 复制代码
function App(props) {
   return (<h1>HELLO</h1>)
}

第0个参数是父组件传来的props

没有string ref,this和生命周期(无状态组件),除了hooks之外所以的变量都会在更新时重新创建(无法在外部定义变量)

尽量避免子函数 每次更新会创建新函数

类式组件

必须继承自React.Component

组件必须定义render方法,写明渲染内容

js 复制代码
import React from 'react'
class App extends React.Component { // 继承自React的组件类
  render() {
    return <h1>HELLO</h1>
  },
  constructor(props) {
    super(props) //继承父组件
  }
}
  • this里有:
    props:父组件传来的数据
    • state: 用于定义和保存数据变量
      可以直接定义,变成类的一个属性
js 复制代码
import React from "react";
// import {Component} from "react"也可以extends Component 
class App extends React.Component {
  state = {
    name: 'ssss',
    num: 1
  }
  render() {
    return <button onClick={}>HELLO</button>
  }
}

修改state:

js 复制代码
setState(
{
// 要修改的state部分
}, 
() => { 
// 状态更新完之后需要执行的回调函数,非必填
}
}

修改state并会重新渲染组件,直接修改this.state 组件不会重新渲染

react会对多次修改合并,只render一次

js 复制代码
setNum= () => { // 事件名称需要驼峰
    let {name,num} = this.state
    this.setState({num: ++num})
  }
  • constructor构造函数
    需要super继承父级
    要定义变量只能在constructor或原型上
    -事件
    没有this,需要用箭头函数

路由和store的包裹关系

index.js

js 复制代码
import store from './redux/index'
import {Provider} from 'react-redux'
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <BrowserRouter><App /></BrowserRouter>
    </Provider>
  </React.StrictMode>
);

store包裹router

react API

组件间通信

  • 子组件-父组件
    把数据和数据更新的回调方法放在props里
js 复制代码
// 父组件
state = {
  openChlid: '1'
}
setOpen=(chlidName) => {
  // 需要绑定this,所以要用箭头函数定义成属性
  this.setSate({
    openChild: chlidName
  })
}
render() {
  return(<List isOpen={openChild === item.name}  date={datas[item]} />)
}
// 子组件
render() {
  let {setOpen} = this.props
  setOpen('1')
}

跨组件
context 不推荐直接在项目中使用

js 复制代码
// --------父组件
import {createContext} from "react";
let {Provider,Consumer} = createContext(defaultVaule) // 可以传默认值 
return (<Provider vaule={{data}}>
  <div><List Consumer={Consumer}/></div>
</Provider>)
// ---------子组件
let {Provider,Consumer} = this.props
return(<Consumer>
  { (props) => {return (<Son {...props} />)} }
</Consumer>)

createContext提供两个组件Provider和Consumer,提供参数的组件用Provider包裹要用到数据的子组件,用vaule属性传参
不结合第三方插件的话,Consumer需要自己做Props传下去
需要使用数据的组件要用Consumer标签包裹,并在箭头函数里返回,回调函数里会有props参数,就是传递的数据

生命周期

react16.3之前

  • 挂载
    constructor() → componentWillMount() → render() → componentDidMount()-
  • 更新阶段:组件因props或state变化而重新渲染
    componentWillReceiveProps(nextProps) (且只有父组件更新引起组件更新会触发)→ shouldComponentUpdate(nextProps, nextState) → componentWillUpdate(nextProps, nextState) → render() → getSnapshotBeforeUpdate() *(16.3之前没有)*→ componentDidUpdate(prepProps, prevState, prevHtml)
    shouldComponentUpdate() { 需要return一个boolean值表示是否更新,return false打断不更新视图}
    16.3之后提供静态方法替代componentWillReceiveProps,但不建议使用,但可以用于state和prop中的数值绑定
js 复制代码
    static getDerivedStateFromProps(props,state) {
        console.log('父组件引起当前组件更新的参数',props, state)
        state.val = props.data.val // 可以用于state和prop中的数值绑定
        return true; // 返回false也没用
    }
  • 卸载阶段:组件从DOM中移除
    componentWillUnmount()
  • 错误处理 16.3之后才有
    在父组件中写,捕获子组件生命周期的错误,不捕获事件中的错误
    static getDerivedStateFromError(error): 静态方法,error是true,方法里返回一个对象可以直接更新组件的state
    componentDidCatch(err, info):API,能拿到this, info能拿到具体的出错信息

受控组件

非受控组件:不需要同步value值的表单控件 用defaultVaule或defaultCheck属性

受控组件:通过onChange事件更新state里的数据的表单控件

PureComponent

和Component比在加载性能上更好,setState提供的是浅比较的shouldComponentUpdate,浅比较相同的不会触发render

state中的引用对象修改记得引用新地址,即使用新对象

children

js 复制代码
// 父组件
render() {
  return(
    <Alert>
      <p>children1</p>
      <p>children2</p>
    </Alert>
   )
}
// Alert子组件
render() {
let {children} = this.props
  return(
    <div>
      <p>...</p>
      {children}
    </div>
   )
}

需要自定义传参的用prop传组件或返回组件的回调函数

js 复制代码
// 父组件
class Btn extends PureComponent {
    render() {
        return(<button onClick={() => {this.props.hide();}}>CLOSE</button>)
    }
}
render() {
  return(
     <Child Child={Btn}}></Child>
     // 或
     <Child renderCb={() => {return <Btn {...this.props}/>}}></Child>
   )
}
// Alert子组件
hide=() => {
        ...
}
render() {
let {Child} = this.props
  return(
    <div>
      <p>...</p>
      <Child hide={() => {this.hide}}></Child>
      // 或
      { renderCb({hide: this.hide}) }
    </div>
   )
}

dangerouslySetInnerHTML

转字符串到html

js 复制代码
import { PureComponent } from "react";
const innerHtmlStr = `<section><h1>11111</h1><section/>`
export default class danger extends PureComponent {
    render() {
        return(<div
          dangerouslySetInnerHTML={{
            __html: innerHtmlStr
          }}
        >
        </div>)
    }
}

refs

在组件挂载、更新完成之后使用
String ref:老版本,不向下兼容

js 复制代码
import { PureComponent } from "react";
export default class danger extends PureComponent {
    render() {
        return(<div>
          <input
             ref="txt" 
          /> 
        </div>)
    }
    componentDidUpdate() {
      this.refs.txt // 对应的dom元素
    }
}

方二 createRef

js 复制代码
import { PureComponent, createRef } from "react";
export default class danger extends PureComponent {
    state = {
        txtRef:createRef()
    }
    render() {
        return(<div>
          <input
            ref={this.state.txtRef} 
          /> 
        </div>)
    }
    componentDidUpdate() {
      this.state.txtRef.current // 对应的dom元素
    }
}

hooks

只能在函数式组件或其他hook里用

只能在顶层使用=不能在if或for里用

use开头的都是钩子函数

react提供的:

useState

sate, setState = useState(initSate)

useState返回的是一个数组,sate当前对应的状态,setState修改对应state的方法

返回的setState也是浅对比

对一个对象useState之后返回的setState是直接替换,而不是合并赋值

js 复制代码
// -------子组件
function Child(props) {
    // const {name, setName} = props;
    const {state, setState} = props;
    let {name, count} = state
    return(<div>
        <p>name: {name}</p>
        <input 
          type="text"
          value={name}
          onChange={(e) => {
            // setName(e.target.value)
            setState({
                ...state, // 对对象使用时是直接替换,需要把原有的加进来
                name: e.target.value
            })
          }}
        ></input>
        <p>count: {count}</p>
        <input 
          type="text"
          value={count}
          onChange={(e) => {
            // setName(e.target.value)
            setState({
                ...state,
                count: e.target.value
            })
          }}
        ></input>
    </div>)
}
// -------父组件
import { useState } from "react"

function HookExp() {
    // const [name, setName] = useState('')
    const [state, setState] = useState({
        name: '',
        count: 1
    })
    return(<div>
        <Child state={state} setState= {setState}/>
    </div>)
}

自定义hook

用use开头,可以提炼重复的单一逻辑

js 复制代码
// 自定义hook
function useToggle(init) {
    const [off, setOff] = useState(init);
    return [off, () => {
        setOff(!off) // 直接取反
    }]
}

// 用的时候
const {show, changeShow} = useToggle(true);

effect

组件加载/更新之后需要的回调

useEffect(cb,监听对象1,监听对象2) // 第二个参数非必传

相当于类组件componentDidMount,componentDidUpdate,componentWillUnmount的时候会执行

js 复制代码
useEffect(() => {
        return () => {
            // 只在组件卸载前执行=componentWillUnmount
        }
    }, [])

    const mountVal = useRef(true)
    useEffect(() => {
        if(!mountVal.current) {
            // 只在组件更新之后执行=componentDidUpdate
            console.log('更新')
        } else {
            // 只在组件挂载时执行=componentDidMount
            console.log('挂载')
            mountVal.current = false
        }
        // 在组件挂载和更新都执行
    })

第二个参数可以指定回调触发的监听对象,但必须是数组形式

js 复制代码
// 监听某个值的更新
useEffect(() => {
        // age改变之后要执行的动作
    }, [name])

useRef

useRef(initRef) 可以获取到真实DOM 并记录组件更新前的值

js 复制代码
// 获取真实dom
    const divRef = useRef(null)
    useEffect(() => {
        console.log(divRef.current)
    }, [])
// 获取组件更新前的变量值
    const {name, setName} = props;
    const [count, setCount] = useState(1)
    const prevVal = useRef({
        name,
        count
    })
    useEffect(() => {
        console.log(prevVal.current) // 获取之前的值
        prevVal.current = {name, count} // 不赋新值的话会一直是初始值
    }, [prevVal])
    return(<div ref={divRef}></div>)

函数式组件定义在hooks外的变量更新会重新创建,也就是回到初始值,变量需要定义在hooks里面,并且在获取之前的值的时候用useRef()

useMemo

组件更新前定义值 useMemo→函数渲染→useEffect

js 复制代码
 const val = useMemo(()=> {
        return `${name}+${count}`
    },[name, count])
    const mountVal = useRef(true)
    useEffect(() => {
        if(mountVal.current) {
            // 只在组件挂载时执行
            console.log('挂载',val) // 已经可以获取到useMemo定义的值
            mountVal.current = false
        }
        // 在组件挂载和更新都执行
    })
相关推荐
用户298698530141 小时前
前端 Excel 处理进阶:React 中合并与取消合并单元格的实现
前端·javascript·react.js
触底反弹1 小时前
面试被问 RAG 只能说出六个字?这篇用 100 行 Node.js 代码帮你彻底搞懂
javascript·人工智能·面试
Highcharts1 小时前
@highcharts/react完整技术指南|新版Highcharts React使用、迁移、SSR、TS 优化全解
前端·javascript
老王以为1 小时前
Fiber 节点 —— 一个数据结构如何承载整个 React 运行时
前端·react native·react.js
gis开发之家1 小时前
vue3组合式函数(Composables)的艺术——将业务逻辑从UI组件中连根拔起
前端·javascript·vue.js·前端框架·vue3·前端工程化·前端架构
mONESY1 小时前
ReAct 智能体循环与 JavaScript 异步并发原理深度解析
react.js
liuniansilence2 小时前
一次讲透 H5 唤起原生 App:Scheme 协议、平台限制与生产级封装
前端·javascript
用户938515635072 小时前
从“问答机器”到“智能体”:AI Agent 是如何自主工作的?
javascript·人工智能·全栈