【React自学笔记06】React18函数式组件知识点合集1

React18函数式组件

  • 基于React18新特性

  • 在原有的React基础上,补充函数式组件的知识点及用法

一、React事件

  • 在React中事件需要通过元素的属性来设置

  • 和原生JS不同,在React中事件的属性需要使用驼峰命名法:

​ onclick -> onClick

​ onchange -> onChange

  • 属性值不能直接执行代码,而是需要一个回调函数,事件触发时执行:

    • onclick="alert(123)"

    • onClick={()=>{alert(123)}}

    • onClick={clickHandler} 不要加括号,加了括号代表调用函数,我们需要的是事件触发才调用

  • 在React中,无法通过在clickHandler函数中return false取消默认行为

    • event.preventDefault(); // 取消默认行为

    • event.stopPropagation(); // 取消事件的冒泡

  • 事件对象event

    • React事件中同样会传递事件对象,可以在响应函数中定义参数来接收事件对象

    • React中的事件对象同样不是原生的事件对象,是经过React包装后的事件对象

    • 由于对象进行过包装,所以使用过程中我们无需再去考虑兼容性问题

二、Props

基础用法

在组件中如果将数据全部写死,将会导致组件无法动态设置,不具有使用价值

我们希望组件数据可以由外部设置,在组件间,父组件可以通过props(属性)向子组件传递数据

父组件中可以直接在子组件标签中设置属性,作为传递的参数值

  • 在函数组件中,属性props就相当于是函数的参数,可以通过参数来访问

  • 可以在函数子组件的形参中定义一个props,props指向的是一个对象

  • 它包含了父组件中传递的所有参数

注意:props只读不能修改

//Logs.js
import LogItem from './LogItem/logItem.js'
const Logs = () => {
  // 模拟一组从服务器中拿回来的数据
  const logsData = [
    {
      id: '001',
      date: new Date(2021, 1, 20, 18, 30),
      desc: '学习九阳神功',
      time: 30
    },
    {
      id: '002',
      date: new Date(2022, 2, 10, 12, 30),
      desc: '学习降龙十八掌',
      time: 20
    }
  ];
  return (
    <div className='logs'>{
      logsData.map((item) => {
        // return <LogItem key={item.id} date={item.date} desc={item.desc} time={item.time} />
        return <LogItem {...item} />
      })
    }
    </div >
  )
}
export default Logs
//LogItem.js
import MyDate from './MyDate/MyDate.js'

import './LogItem.css'
const LogItem = (props) => {
  return (
    <div className='item'>
      <MyDate date={props.date}/>
      <div className='content'>
        <h2 className="desc">{props.desc}</h2>
        <div className="time">{props.time}分钟</div>
      </div>
    </div>
  )
}
export default LogItem
import './MyDate.css'
const MyDate = (props) => {
  const month = props.date.toLocaleString('zh-CN', { month: 'long' })
  const day = props.date.getDate()
  return (
    <div className='date'>
      <div className='month'>{month}</div>
      <div className='day'>{day}</div>
    </div>
  )
}
export default MyDate

传递标签体

怎么把标签体传给card:props.className

//Card.js
import './Card.css'
const Card=(props)=>{
  return (
    <div className={`${props.className} card`}>{props.children}</div>
  )
}
export default Card

三、State

在React中,当组件渲染完毕后(先执行),再修改组件中的变量(后执行),不会使组件重新渲染;要使得组件可以受到变量的影响,必须在变量修改后对组件进行重新渲染;这里我们就需要一个特殊变量,当这个变量被修改时,组件会自动重新渲染。

state相当于一个变量,只是这个变量在React中进行了注册,React会监控这个变量的变化,当state发生变化时,会自动触发组件的重新渲染,使得我们的修改可以在页面中呈现出来。

注意:props是传给别人用的,state是对当前组件自身的属性(state是可变的,只属于当前属性)

📌定义步骤:

  • 在函数组件中,我们需要通过钩子函数,获取state;

  • 使用钩子 useState() 来创建state;

  • 导入包:import {useState} from "react";

    • useState()需要一个值作为参数,这个值就是state的初始值

      • 该函数会返回一个数组

      • 数组中第一个元素,是初始值,初始值只用来显示数据,直接修改不会触发组件的重新渲染

      • 数组中的第二个元素,是一个函数,通常会命名为setXxx,这个函数用来修改state,调用其修改state后会触发组件的重新渲染(重新调用render),并且使用函数中的值作为新的state值

import { useState } from "react";
import './counter.css'
const Counter = () => {
  const [counter, setCounter] = useState(1);
  const addHandler = () => {
    setCounter(counter + 1)
  }
  const minusHandler = () => {
    setCounter(counter - 1)
  }
  return (
    <div className="counter">
      <h2>{counter}</h2>
      <button onClick={addHandler}>+</button>
      <button onClick={minusHandler}>-</button>
    </div>
  )
}
export default Counter

💕总结:

state实际就是一个被React管理的变量;当我们通过setState()修改变量的值时,会触发组件的自动重新渲染;只有state值发生变化时,组件才会重新渲染

当state的值是一个对象时,修改时是使用新的对象去替换已有对象

  • setUser({...user, name: '猪八戒'});

  • const newUser = Object.assign({}, user);

    newUser.name = '猪八戒';

    setUser(newUser);

如果直接修改旧的state对象,由于对象还是那个对象,所以不会生效

  • user.name = '猪八戒';
  • setUser(user);

当通过setState去修改一个state时,并不表示修改当前的state,counter的初始值并没有改变;它修改的是组件下一次渲染时state值

setState()会触发组件的重新渲染,它是异步的;调完setState组件并不是立刻调用render函数进行渲染,而是先挂载到队列中,直到代码所有都执行完成再执行队列

所以当调用setState()需要用旧state的值时,一定要注意,有可能出现计算错误的情况;为了避免这种情况,可以通过为setState()传递回调函数的形式来修改state值

    const addHandler = () => {
        setTimeout(() => {
            setCounter((prevCounter)=>{
                /*
                *   setState()中回调函数的返回值将会成为新的state值
                *       回调函数执行时,React会将最新的state值作为参数传递
                * */
                return prevCounter + 1;
            });
            // setCounter(prevState => prevState + 1);
        }, 1000);
    };

只要用到之前的值就传回调

四、Ref

useRef()返回的就是一个普通的JS对象 {current:undefined},所以我们直接创建一个js对象,也可以代替useRef()

const h1Ref = {current:null};

const h1Ref = useRef(); // 创建一个容器

区别:

  •   我们创建的对象,组件每次重新渲染都会创建一个新对象
    
  •   useRef()创建的对象,可以确保每次渲染获取到的都是同一个对象
    
  •   当需要一个对象不会因为组件的重新渲染而改变时,就可以使用useRef()
    

📌 获取原生的DOM对象步骤

  • 1.创建一个存储DOM对象的容器

    • 使用 useRef() 钩子函数

      • ① React中的钩子函数只能用于函数组件或自定义钩子

      • ② 钩子函数只能直接在函数组件中调用

  • 2.将容器设置为想要获取DOM对象元素的ref属性

    • React会自动将当前元素的DOM对象,设置为容器current属性
  • 代码:

    < h1 id="header" ref={h1Ref}>我是标题{count}</ h1>

    h1Ref.current.innerText = '嘻嘻!';

五、受控/非受控组件

非受控组件:监听表单项的变化

  • 创建三个变量,用来存储表单中的数据

  • 创建一个响应函数,监听相关数据的变化

    • 函数的参数为e:当前触发事件的对象,事件对象中保存了当前事件触发时的所有信息

    • event.target 执行的是触发事件的对象(DOM对象)

  • 在React中,通常表单不需要自行提交,而是要通过React提交

    • 取消表单的默认行为

    • 获取表单项中的数据

    • 将数据拼装为一个对象

//LogsForm.js
import Card from "../UI/Card"
import './LogsForm.css'
const LogsForm = () => {
  let inputDate = ''
  let inputDesc = ''
  let inputTime = 0
  const dateChangeHandler = (e) => {
    inputDate = e.target.value
  }
  const descChangeHandler = (e) => {
    inputDesc = e.target.value
  }
  const timeChangeHandler = (e) => {
    inputTime = e.target.value
  }
  const formSubmitHandler=(e)=>{
    e.preventDefault()
    const newLog={
      date:new Date(),
      desc: inputDesc,
      time: +inputTime
    }
  }
  return (
    <Card className="logs-form">
      <form onSubmit={formSubmitHandler}>
        <div className="form-item">
          <label htmlFor="date">日期</label>
          <input id="date" type="date" onChange={dateChangeHandler} />
        </div>
        <div className="form-item">
          <label htmlFor="desc">内容</label>
          <input id="desc" type="text" onChange={descChangeHandler} />
        </div>
        <div className="form-item">
          <label htmlFor="time">时长</label>
          <input id="time" type="number" onChange={timeChangeHandler} />
        </div>
        <div className="form-btn">
          <button >添加</button>
        </div>
      </form>
    </Card>
  )
}
export default LogsForm

受控组件(双向绑定)

将表单中的数据存储到state中,然后将state设置为表单项value值,当表单项发生变化,state会随之变化,反之,state发生变化,表单项也会跟着改变

state提升,提升到共用组件里

//app.js
import LogsForm from './Components/LogsForm/LogsForm'
import Logs from './Components/Logs/Logs'
import Counter from './Components/Counter/Counter.js'
import { useState } from 'react';
import './app.css'
const App = () => {
  // 模拟一组从服务器中拿回来的数据
  const [logsData, setLogsData] = useState([
    {
      id: '001',
      date: new Date(2021, 1, 20, 18, 30),
      desc: '学习九阳神功',
      time: 30
    },
    {
      id: '002',
      date: new Date(2022, 2, 10, 12, 30),
      desc: '学习降龙十八掌',
      time: 20
    }
  ])
  const saveLogHandler = (newLog) => {
    let id = Date.now() + ''
    newLog = { id, ...newLog }
    setLogsData([...logsData, newLog])
  }
  return (
    <div className='app'>
      <LogsForm onSaveLog={saveLogHandler} />
      <Logs logsData={logsData} />
      <Counter />
    </div>
  )
}
export default App
//Logs.js
props.onSaveLog(newLog)

===================================================
隔一段时间看受控组件已经看不懂自己的笔记了,重新补充一下

import React, {useState} from 'react';
import Card from "../UI/Card/Card";
import './LogsForm.css';

const LogsForm = () => {

    /*
    *   当表单项发生变化时,获取用户输入的内容
    *   非受控组件中是用let定义变量来存储表单数据的 let inputDate = '';
    *   但是在受控组件中,是用useState来定义的
    * */
    const [inputDate, setInputDate] = useState('');
    const [inputDesc, setInputDesc] = useState('');
    const [inputTime, setInputTime] = useState('');

    // 创建一个响应函数,监听日期的变化
    const dateChangeHandler = (e) => {
        // 获取到当前触发事件的对象
        // 事件对象中保存了当前事件触发时的所有信息
        // event.target 执行的是触发事件的对象(DOM对象)
        // 在受控组件中使用setState来改变state的值,在非受控组件中使用变量赋值的方式
        setInputDate(e.target.value);
    };

    // 监听内容的变化
    const descChangeHandler = (e) => {
        setInputDesc(e.target.value);
    };

    //监听时长的变化
    const timeChangeHandler = (e) => {
        setInputTime(e.target.value);
    };

    // 当表单提交时,汇总表单中的数据
    /*
    *   在React中,通常表单不需要自行提交
    *       而是要通过React提交
    * */
    const formSubmitHandler = (e) => {
        // 取消表单的默认行为
        e.preventDefault();
        // 获取表单项中的数据日期、内容、时长
        // 将数据拼装为一个对象
        const newLog = {
            date: new Date(inputDate),
            desc: inputDesc,
            time: +inputTime
        };

        // 清空表单项
        setInputDate('');
        setInputDesc('');
        setInputTime('');

        console.log(newLog);

        /*
        *   提交表单后如何清空表单中的旧数据
        *       现在这种表单,在React我们称为非受控组件
        *
        *   我们可以将表单中的数据存储到state中,
        *       然后将state设置为表单项value值,
        *       这样当表单项发生变化,state会随之变化,
        *       反之,state发生变化,表单项也会跟着改变,这种操作我们就称为双向绑定
        *       这样一来,表单就成为了一个受控组件
        *
        * */

    };

    return (
        <Card className="logs-form">
            <form onSubmit={formSubmitHandler}>
                <div className="form-item">
                    <label htmlFor="date">日期</label>
                    <input onChange={dateChangeHandler} value={inputDate} id="date" type="date"/>
                </div>
                <div className="form-item">
                    <label htmlFor="desc">内容</label>
                    <input onChange={descChangeHandler} value={inputDesc} id="desc" type="text"/>
                </div>
                <div className="form-item">
                    <label htmlFor="time">时长</label>
                    <input onChange={timeChangeHandler} value={inputTime} id="time" type="number"/>
                </div>
                <div className="form-btn">
                    <button>添加</button>
                </div>
            </form>
        </Card>
    );
};

export default LogsForm;

====================================================

六、创建React项目

手动创建项目

  • 创建项目,目录结构如下

    • public

      • index.html

        <!DOCTYPE html>
        <html lang="zh">
        <head>
           <meta charset="UTF-8">
           <title>Title</title>
        </head>
        <body>
        <div id="root"></div>
        </body>
        </html>
        
    • src

      • App.js

        const App = () => {
           return <h1>Hello React!</h1>
        }
        export default App;
        
      • index.js

        import ReactDOM from "react-dom/client";
        import App from "./App";
        
        const root = ReactDOM.createRoot(document.querySelector('#root'));
        root.render(element);
        
  • 进入项目所在目录,执行npm init -yyarn init -y

  • 安装项目依赖:npm install react react-dom react-scripts -Syarn add react react-dom react-scripts

  • 运行npx react-scripts start启动项目(初次启动需要输入y确认)

  • 可以配置package.json

    "scripts": {

    "start": "react-scripts start",

    },

自动创建项目

运行 npx react-scripts start

创建npx create-react-app 项目名字

启动 npm start

posted @   Lu西西  阅读(597)  评论(0编辑  收藏  举报
相关博文:
点击右上角即可分享
微信分享提示