当前位置: 首页 > news >正文

千峰React:函数组件使用(2)

前面写了三千字没保存,恨!

批量渲染

function App() {
    const list = [
      {id:0,text:'aaaa'},
      {id:1,text:'bbbb'},
      {id:2,text:'cccc'}
  ]
  //   for (let i = 0; i < list.length; i++) {
  //     list[i] = <li>{list[i]}</li>
  //   }
  return (
    <div>
      <ul>
        {list.map((item) => <li key={item.id}>{item.text}</li>)}
      </ul>
    </div>
  )
}
export default App

点标记写法

// function Welcome() {
//   return <div>hello Welcome</div>
// }

// function App() {
//   return (
//     <div>
//       <Welcome />
//       <Welcome></Welcome>
//     </div>
//   )
// }
// export default App

const Qf = () => {
  return <div>hello Qf</div>
}

Qf.Welcome = () => {
  return <div>hello Welcome</div>
}


function App() {
  return (
    <div>
      <Qf.Welcome />
      <Qf.Welcome></Qf.Welcome>
    </div>
  )
}
export default App

组件通信

import PropTypes from 'prop-types'
//子组件
function Welcome({ count, msg,isShow }) {
  return (
    <div>
      hello Welcome,{count},{msg},{isShow+''}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  msg: PropTypes.string.isRequired, // 验证 msg 是字符串并且是必传的
  isShow: PropTypes.string.isRequired, // 验证isShow是字符串并且是必传的
}

//父组件
function App() {
    const count='我是个变量'
  return (
    <div>
      <Welcome count={count} msg='hi react' isShow />
    </div>
  )
}
export default App

组件组合

import PropTypes from 'prop-types'
//子组件
function Welcome() {
  return <div>hello Welcome</div>
}

function Head() {
  return <div>hello Head</div>
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  msg: PropTypes.string.isRequired, // 验证 msg 是字符串并且是必传的
  isShow: PropTypes.string.isRequired, // 验证isShow是字符串并且是必传的
}

//父组件
function App() {
  return (
    <div>
      hello App
      <Welcome>
        <Head />
      </Welcome>
    </div>
  )
}
export default App

可以看见这个Head被包在Welcome里 是渲染不出来的

使用props的children属性传递子组件

import PropTypes from 'prop-types'

function Head() {
  return <div>hello Head</div>
}

function Welcome({ children }) {
  return (
    <div>
      hello Welcome
      {children}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  children: PropTypes.string.isRequired, 
}

//父组件
function App() {
  return (
    <div>
      hello App
      <Welcome>
        <Head />
      </Welcome>
    </div>
  )
}
export default App

另一种写法

import PropTypes from 'prop-types'

function Head({ count }) {
  return <div>hello Head,{count}</div>
}

function Welcome() {
  const count = 456
  return (
    <div>
      hello Welcome
      <Head count={count} />
    </div>
  )
}
// 为 Head 组件添加 prop-types 验证
Head.propTypes = {
  count: PropTypes.number.isRequired, // 验证 count 是数字并且是必传的
}

// 添加 prop-types 验证
Welcome.propTypes = {
}

//父组件
function App() {
  return (
    <div>
      hello App
      <Welcome>
        <Head />
      </Welcome>
    </div>
  )
}
export default App

import PropTypes from 'prop-types'

// 为 Head 组件添加 prop-types 验证
Head.propTypes = {
  count: PropTypes.number.isRequired, // 验证 count 是数字并且是必传的
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.number.isRequired, // 验证 Welcome 组件的 count 是必传的
}

function Head({ count }) {
  //接收count
  return <div>hello Head,{count}</div>
}

function Welcome() {
  const count = 456
  return (
    <div>
      hello Welcome
      <Head count={count} />
      {/* {挂载count} */}
    </div>
  )
}

//父组件
function App() {
  const count = 123
  return (
    <div>
      hello App
      <Welcome count={count} />
    </div>
  )
}
export default App

如何分别传递多组内容

所有的内容放到children里,没办法独立使用

import PropTypes from 'prop-types'

function Welcome({ children }) {
  return (
    <div>
      {children}
      hello Welcome
      {children}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  children: PropTypes.string.isRequired,
}

//父组件
function App() {
  return (
    <div>
      hello App
      <Welcome>
        <div>aaaaaaaaaaaa</div>
        <div>bbbbbbbbbbbb</div>
      </Welcome>
    </div>
  )
}
export default App

使用多组内容传递

import PropTypes from 'prop-types'

function Welcome({ bottom, top }) {
  return (
    <div>
      {top}
      hello Welcome
      {bottom}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  children: PropTypes.string.isRequired,
  top: PropTypes.string.isRequired,
  bottom: PropTypes.string.isRequired,
}

//父组件
function App() {
  return (
    <div>
      hello App
      <Welcome
        top={<div>aaaaaaaaaaaa</div>}
        bottom={<div>bbbbbbbbbbbb</div>}
      ></Welcome>
    </div>
  )
}
export default App

通信的数据如何添加默认值

import PropTypes from 'prop-types'

function Welcome({ count, msg }) {
  return (
    <div>
      hello Welcome,{count},{msg}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  children: PropTypes.string.isRequired,
  msg: PropTypes.string.isRequired,
}

//父组件
function App() {
  return (
    <div>
      hello App
      {/* { 传递参数的情况} */}
      <Welcome count={123} msg='hello react' />
      {/* { 不传递参数的情况} */}
      <Welcome />
    </div>
  )
}
export default App

如果有接收参数的位置,但是不传递参数,就会这样👇

为了解决这个问题,就提供了默认参数

ES6是这么做的:

import PropTypes from 'prop-types'

// function Head() {
//   return <div>hello Head</div>
// }

function Welcome({ count='我是count的默认值', msg='我是msg的默认值'}) {
  return (
    <div>
      hello Welcome,{count},{msg}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的
  children: PropTypes.string.isRequired,
  msg: PropTypes.string.isRequired,
}

//父组件
function App() {
  return (
    <div>
      hello App
      {/* { 传递参数的情况} */}
      <Welcome count={123} msg='hello react' />
      {/* { 不传递参数的情况} */}
      <Welcome />
    </div>
  )
}
export default App

也可以使用React原生的:

import PropTypes from 'prop-types'

function Welcome({ count,msg}) {
  return (
    <div>
      hello Welcome,{count},{msg}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.number, // 验证 count 是数字(非必传)
  msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}

Welcome.defaultProps = {
    count: 0,
    msg:'我是默认值'
}
//父组件
function App() {
  return (
    <div>
      hello App
      {/* { 传递参数的情况} */}
      <Welcome count={123} msg='hello react' />
      {/* { 不传递参数的情况} */}
      <Welcome />
    </div>
  )
}
export default App

但是我失败了

为什么?因为:

我是19,别管了就用es6吧

通信数据如何限定类型

一般更推荐ts,但是ts不一定是项目用的

类型验证就用我之前已经写过的这部分👇

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.number, // 验证 count 是数字(非必传)
  msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}

浏览器莫名其妙不报错,可能还是react的版本问题

如果希望有个数据传过来,数字和字符串都是符合要求的类型,也就是筛出两种类型可以这么写:

// 添加 prop-types 验证
Welcome.propTypes = {
    count:PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
  ]),// 验证 count 是数字或字符串(非必传)
  msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}

还可以有一些更复杂的限定,比如限定值是多少:

import PropTypes from 'prop-types'

function Welcome({ count, msg }) {
  return (
    <div>
      hello Welcome,{count},{msg}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // 验证 count 是数字或字符串(非必传)
  msg: PropTypes.string, // 验证 msg 是字符串(非必传)
  type: PropTypes.oneOf(['primary', 'success', 'error']),
}

Welcome.defaultProps = {
  count: 0,
  msg: '我是默认值',
}
//父组件
function App() {
  return (
    <div>
      hello App
      {/* { 正确的情况} */}
      <Welcome count={123} msg='hello react' type='我是错的' />
    </div>
  )
}
export default App

这里按理来说应该会报错,但是并没有!!!

传值其实也可以传jsx:

import PropTypes from 'prop-types'

function Welcome({ count, msg }) {
  return (
    <div>
      hello Welcome,{count},{msg}
    </div>
  )
}

// 添加 prop-types 验证
Welcome.propTypes = {
  count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // 验证 count 是数字或字符串(非必传)
  msg: PropTypes.string, // 验证 msg 是字符串(非必传)
  type: PropTypes.oneOf(['primary', 'success', 'error']),
  icon: PropTypes.element//针对jsx的类型,element
}

Welcome.defaultProps = {
  count: 0,
  msg: '我是默认值',
}
//父组件
function App() {
  return (
    <div>
      hello App
      {/* { 正确的情况} */}
      <Welcome
        count={123}
        msg='hello react'
        type='primary'
        icon={<div className='icon-close'></div>}
      />
    </div>
  )
}
export default App

组件必须是个纯函数

react的严格模式会检测我们当前的组件是不是纯函数

纯函数组件是指:

  • 组件的输出(渲染结果)完全由输入(props 和 state)决定。

  • 组件没有副作用(例如直接修改 DOM、发起网络请求、使用 setTimeout 等)。

  • 组件在相同的 props 和 state 下,总是返回相同的渲染结果

两次结果一样

在严格模式下,React 会 故意调用两次 函数组件(包括其渲染逻辑),如果组件是纯函数,两次调用的结果应该完全相同。

比如++操作,如果把对count的声明写函数外面,那么就不是一个纯函数:

预期来说count=2,最后等于3是因为React故意调用两次函数组件,两次的结果一次为2,一次为3,所以不是纯函数组件

这样就是了

function App() {
  let count = 1
  count++
  console.log(count)

  return <div>{count}</div>
}
export default App

两次结果相同

当然,不开严格模式的话就没有这种情况啦,一般建议开启

相同的输入和输出

意思就是给函数传入相同的参数,就应该传出相同的输出

这是一个纯函数,传入2都是4

这不是纯函数,传入2得到的输出不一定相同

纯函数可以保证我们的组件更健壮

组件的状态和useState

 useState基础使用

useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量(State), 从而控制影响组件的渲染结果

状态变量是 React 组件内部的一个特殊变量,用于存储组件的数据,当状态变量的值发生变化时,React 会自动重新渲染组件,以反映最新的数据

状态变量和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)

useState是React里的方法,返回的是个数组,数组里有两项:[状态变量,修改状态变量的方法]

只有用这个专门的修改状态变量的方法修改变量,才会在ui渲染里起效

//useState实现一个计数器按钮
import { useState } from 'react'
function App() {
  // const handleClick = (name,e) => console.log('button被点击了name:',name,'e:',e)

  //1、调用useState添加一个状态变量
  const [count, setCount] = useState(0)
  //2、点击事件回调
  const handleClick = () => { setCount(count+1) }
  return (
    <div className="App">
      <button onClick={handleClick}>{count}</button>
    </div>
  );
}
export default App;

count++ 会直接修改 count 的值,而 React 的状态变量是不可变的(Immutable),不能直接修改。

那我就要问了:const handleClick = () => { setCount(count++) }这么写不也是通过setState 函数更新状态吗?为什么不行?

count++ 会先返回当前的值,再进行自增操作,而 React 的 setState 需要传入新的值,而不是修改原值。

那++count呢?++count 会先对 count 进行自增操作,然后返回自增后的值。这个操作会直接修改当前 count 的值,而 React 需要的是通过 setCount 来触发状态的更新,这就相当于状态变量的修改是你自己改的,不是通过对应的方法改的

正确的写法是应该直接传入 count + 1,而不是 count++,因为 count++ 只是修改了本地变量

对于对象来说也是这样,应该把新的对象写进对应方法,而不是直接修改

import { useState } from 'react'

function App () {
  let [count, setCount] = useState(0)

  const handleClick = () => {
    // 直接修改 无法引发视图更新
    // count++
    // console.log(count)
    setCount(count + 1)
  }

  // 修改对象状态
  const [form, setForm] = useState({ name: 'jack' })

  const changeForm = () => {
    // 错误写法:直接修改
    // form.name = 'john'
    // 正确写法:setFrom 传入一个全新的对象
    setForm({
      ...form,
      name: 'john'
    })
  }

  return (
    <div>
      <button onClick={handleClick}>{count}</button>
      <button onClick={changeForm}>修改form{form.name}</button>
    </div>
  )
}

export default App

状态如何改变视图

先看这段代码

function App() {
  let count = 0

  const increment = () => {
    count++ // 修改普通变量
    console.log(count) // 值会变化,但不会触发重新渲染
  }
  console.log(1234567)

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  )
}
export default App

    点击按钮时,count 的值会增加,但页面不会重新渲染,因此用户看不到变化。

    状态变量会被记忆上一次的值,每次渲染函数返回的内容不一样,所以在察觉变化的时候React会重新调用渲染函数,并且改变count,所以每次结果都不一样)

    普通变量的变化不会通知 React,所以React 不会调用渲染函数,所以不会重新渲染jsx。

    顺便:Mujica第八集拍出来其实是为了缩短中国人寿命降低生产力,是日本人为了打败中国人投放的精神类武器,是日本成为东亚第一强国的邪恶计划最核心的一步

    相关文章:

  • GIS地图、轨道交通与智能驾驶UI设计:未来交通的智能化探索
  • TPU(Tensor Processing Unit)详解
  • nnUNet V2修改网络——加入MultiResBlock模块
  • 1.25作业
  • 注意力机制进化史:从MHA到MoBA,新一代注意力机制的极限突破!
  • 计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)
  • Python zip 函数详解:用法、应用场景与高级技巧(中英双语)
  • 现代Web开发工具与技术全解析
  • 毕业项目推荐:基于yolov8/yolov5/yolo11的非机动车头盔佩戴检测识别系统(python+卷积神经网络)
  • 将产品照片(form.productPhotos)转为 JSON 字符串发送给后端
  • 【JavaEE进阶】图书管理系统 - 贰
  • C语言中的链表封装
  • 网络工程知识笔记
  • ChatGPT客户端无法在微软应用商店下载的解决方法
  • IntelliJ IDEA 控制台输出中文出现乱码
  • 基于stm32的多旋翼无人机(Multi-rotor UAV based on stm32)
  • Embedding模型
  • (二)趣学设计模式 之 工厂方法模式!
  • 行业分析---对自动驾驶规控算法未来的思考
  • 【02.isaac-gym】最新从零无死角系列-(00) 目录最新无死角环境搭建与仿真模拟
  • 特朗普宣布提名迈克·沃尔兹为下一任美国驻联合国大使
  • 解放日报:让算力像“水电煤”赋能千行百业
  • 马上评|扩大高速免费救援范围,打消出行后顾之忧
  • 十大券商看后市|A股风险偏好有望边际改善,市场仍处黄金坑
  • 俄罗斯称已收复库尔斯克州
  • “70后”通化市委书记孙简已任吉林省政府领导