React框架对前端开发的意义
1.页面组件化
组件化使用更加方便,维护更加容易,适合做复用:在其他页面也可以使用。
React函数组件(首字母要大写)
组件被调用的位置,填入的就是组件返回的部分。
2.数据驱动视图
数据的变化会引起视图的变化,对数据修改后React会修改Dom元素。
style样式
行间样式、全局样式、局部样式
行间样式
function App(){
const myStyle={width: '100px',height: '100px' ,background:'red'}
return (
<div style={myStyle}>hello App</div>
)
}
export default App
全局样式
import "全局样式.css"
function App(){
return(
<>
<div className="box3"> aaaaaaaa</div>
</>
)
}
export default App
全局样式.css
.box{
width: 300px;
height: 100px;
background: blue;
}
局部样式
import sytle from '局部样式.module.css' function App(){ return( <> <div className={sytle.box2}>aaaaaaaaaa</div> </> ) } export default App
局部样式.css
.box2{background:green; color: white;} .head-title{ background: pink; } .head-title-icon{ background: yellow; }
className模块
安装:
npm i classnames
引入:
import classNames from {classnames}
示例:
import style from '局部样式.module.css' import classNames from "classnames" function App () { const myClass = classNames({ box1: true, box2: false, [style.headTitle]: true }) return ( <> <div className={myClass}> hello App </div> </> ) } export default App
事件
事件的概念:
在编程中,事件是指在特定情况下发生的动作,如用户点击按钮、提交表单、移动鼠标等。在 React 中,事件是用户与组件交互的触发点。通过处理事件,开发者可以对用户的操作做出响应,从而更新 UI、发送网络请求、或执行其他逻辑。
在react中事件的命名要采用小驼峰式的写法。
在 React 中,事件处理函数是响应用户交互的主要方式。添加事件处理函数非常简单,通常通过 JSX 属性进行绑定。
示例
function App(){ const headleClick=()=>{ console.log(123) } const headleClick2=(num)=>{ return ()=>{ console.log(num) } } const headleClick3=(num,e)=>{ console.log(num,e) } return ( <div> hello app <button onClick={headleClick}>点击</button> <button onClick={headleClick2(123)}>点击2-传参</button> <button onClick={(e)=>headleClick3(123,e)}>点击3-传参</button> <button onClick={headleClick3}>点击4-传参</button> </div> ) } export default App
我们把事件中的函数部分抽离出去,用变量来表示。
条件渲染
1.使用if-else
function App () { let content let count = 0 if( count > 1 ) { content = <div>hello react</div> } else { content = <p>hi JavaScript</p> } return ( <div> Hello App <br /> { content } </div> ) } export default App
2.条件运算符: ? :
function App() { let count = 5 return ( <div> Hello App <br /> {count > 3 ? <div>hello react</div> : <p>hi JavaScript</p>} </div> ) } export default App
3.逻辑运算符: &&,||
function App() { // && || -> 适合做一个条件的渲染 // 而 if else 和 ? : -> 适合做多个条件的渲染 let count = 0 return ( <div> Hello App <br /> {count > 3 && <div>hello React</div>} </div> ) } export default App
列表渲染
方法1.for ,while
function App () { const list = ['aaaa', 'bbbb', 'cccc'] for(let i=0;i<list.length;i++) { list[i] = <li>{ list[i] }</li> } return ( <div> hello App <br /> <ul> { list } </ul> </div> ) } export default App
方法2.map
function App () { const list = ['aaaa', 'bbbb', 'cccc'] return ( <div> hello App <br /> <ul> { list.map((item) => <li>{item}</li>) } </ul> </div> ) } export default App
方法3.key
function App () { const list = [ { id: 0, text: 'aaaa' }, { id: 1, text: 'bbbb' }, { id: 2, text: 'cccc' }, ] return ( <div> hello App <br /> <ul> { list.map((item, index) => <li key={item.id}>{item.text}</li>) } </ul> </div> ) } export default App
key方法的好处:这些key会告诉React,每个组件对应着数组里的哪一项,可以帮助React推断发生了什么,从而得以正确的更新DOM树。
使用json中的id作为key的好处:当列表出现删除时,key不会因为索引值的 变化而改变。
组件的点标记写法
对象形式
const Qf = { Welcome() { return ( <div> hello Welcome </div> ) } } const { Welcome } = Qf function App () { return ( <div> hello App <br /> <Qf.Welcome /> <Welcome /> </div> ) } export default App
函数形式
const Qf = () => { return ( <div> hello Qf </div> ) } Qf.Welcome = () => { return ( <div> hello Welcome </div> ) } const { Welcome } = Qf function App () { return ( <div> hello App <br /> <Qf /> <Qf.Welcome /> <Welcome /> </div> ) } export default App
组件间的通信
使用props
1.整体接收
// 子组件 -> 整体接收 function Welcome (props) { return ( <div> hello Welcome, { props.count }, { props.msg } </div> ) } // 父组件 function App () { return ( <div> hello App <Welcome count="123" msg="hi react" /> </div> ) } export default App
2.解构接收
// 当传递的数据,只有属性名没有值,那么就是传递了一个布尔值true过来 function Welcome ({ count, msg, isShow }) { return ( <div> hello Welcome, { count }, { msg }, { isShow + '' } </div> ) } // 父组件 function App () { const count = 123 return ( <div> hello App <Welcome count={count} msg="hi react" isShow /> </div> ) } export default App
3.传递事件,函数
function Welcome ({ onClick, getData }) { getData('我是子组件的数据') return ( <div onClick={onClick}> hello Welcome </div> ) } // 父组件 function App () { const count = 123 const handleClick = () => { console.log(1234) } const getData = (data) => { console.log(data) } return ( <div> hello App <Welcome onClick={handleClick} getData={getData} /> </div> ) } export default App */
4.使用{...}批量传输数据
// 子组件 function Welcome ({ count, msg, num, id }) { return ( <div> hello Welcome, { count }, { msg }, { num }, { id } </div> ) } // 父组件 function App () { const info = { count: 123, msg: 'hi react', num: 456, id: 789 } return ( <div> hello App <Welcome {...info} /> </div> ) } export default App
5.添加默认值
a.解构式的添加
function Welcome ({ count=0, msg='default content' }) { return ( <div> hello Welcome, { count }, { msg } </div> ) }
b.使用defaultProps属性
function Welcome ({ count, msg }) { return ( <div> hello Welcome, { count }, { msg } </div> ) } Welcome.defaultProps = { count: 0, msg: 'default content' } function App () { return ( <div> hello App <Welcome count={123} msg="hello react" /> <Welcome /> </div> ) } export default App
6.限定通信时的数据类型
组件的PropTypes属性
import PropTypes from 'prop-types' function Welcome ({ count, msg }) { return ( <div> hello Welcome, { count }, { msg } </div> ) } Welcome.propTypes = { //count: PropTypes.number count: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, ]), type: PropTypes.oneOf(['primary', 'success', 'error']), icon: PropTypes.element } function App () { return ( <div> hello App <Welcome count={'123'} msg="hello react" type="primary" icon={ <div className="icon-close">✖</div> } /> </div> ) } export default App
组件组合
props的children属性
function Head ({ count }) { return ( <div> hello Head, { count } </div> ) } function Welcome ({ children }) { const count = 456 return ( <div> hello Welcome { children } </div> ) } function App () { const count = 123 return ( <div> hello App <Welcome> <Head count={count} />//作用域来自于当前的数据 </Welcome> </div> ) } export default App
输出123
function Head ({ count }) { return ( <div> hello Head, { count } </div> ) } function Welcome () { const count = 456 return ( <div> hello Welcome <Head count={count} />//在挂载count时,使用当前作用域的count </div> ) } function App () { const count = 123 return ( <div> hello App <Welcome /> </div> ) } export default App
输出456
分别传递多组数据:直接写在welcom组件里,用属性挂载jsx
function Welcome ({ top, bottom }) { return ( <div> { top } hello Welcome { bottom } </div> ) } function App () { return ( <div> hello App <Welcome top={<div>aaaaaaaaaaa</div>} bottom={<div>bbbbbbbbbbb</div>} /> </div> ) } export default App
组件必须是一个纯函数
纯函数
1.只负责自己的任务,它不会更改在该函数调用前就已经存在的变量和对象
// 不纯的函数 let bar = 1 function foo() { bar++ } foo() // 纯函数 function foo() { let bar = 1 bar++ } foo()
2.输入相同,则输出相同。给定相同的输入,纯函数总是返回相同的结果
// 不纯的函数 function foo(n) { return Math.random() } foo(2) foo(2) foo(2) // 纯函数 function foo(n) { return n * 2 } foo(2) foo(2) foo(2)
状态和变量的区别
随时间变化的数据称为状态(state),状态是可以驱动视图的,而普通变量不行
useState:引入状态的钩子,可以创建状态和修改状态的方法。
const [count ,setCount]=useState(0) const [状态,改变状态的方法]=useState(初始值)
为什么普通变量不能改变视图?
:因为不会重新渲染jsx
为什么state状态可以改变视图?
重新触发函数组件,并且state状态具备组件的记忆。
状态如何改变视图?
1.触发一次渲染:a.如果是组件的初次渲染:createRoot().render() 。b.内部状态更新时,触发渲染送入队列。
2.渲染组件:a.初次时:调用根组件。b.更新时:重新执行函数
3.提交到DOM上:a.初次时:appendChild( ) DOM API b. 更新时:更新有差异的DOM节点
多状态是如何进行正确记忆的
在同一组件的每次渲染中,useState都依托于一个稳定的调用顺序
import { useState } from 'react' function App() { const [count, setCount] = useState(0) const [count2, setCount2] = useState(0) const [count3, setCount3] = useState(0) const handleClick = () => { setCount(count + 1) } return ( <div> hello App <button onClick={handleClick}>点击</button> {count}, {count2}, {count3} </div> ) } export default App
在React内部,为每一个组件保存了一个数组,其中每一项都是一个state对。它维护当前state对的索引值,在渲染之前将其设置为0,每次调用useState时,React都会为你提供一个state对并增加索引值。
不要在逻辑中使用useState,会打乱调用顺序
import { useState } from 'react' let num = 0 function App() { const [count, setCount] = useState(0) if(num == 0) { const [count2, setCount2] = useState(0) } const [count3, setCount3] = useState(0) const handleClick = () => { setCount3(count3 + 1) setCount(2) num++ } return ( <div> hello App <button onClick={handleClick}>点击</button> {count}, {count3} </div> ) } export default App
状态的快照
useState实际上是生成了一张快照,在整个代码中使用的都是这张快照,count的改变发生在下一次刷新时。
import { useState } from "react" function App () { const [count, setCount] = useState(0) const handleClick = () => { setCount(count + 1)//1 setCount(count + 1)//1 setCount(count + 1)//1 console.log( count )//1 } return ( <div> hello App <button onClick={handleClick}>点击</button> { count } </div> ) } export default App
状态队列与自动批处理
自动批处理:
合并多个setState()、只触发一次render() 保证了性能
import { useState } from "react" function App () { const [count, setCount] = useState(0) const handleClick = () => { setCount(count + 1) setCount(count + 1) setCount(count + 1) console.log( count ) } console.log(123) return ( <div> hello App <button onClick={handleClick}>点击</button> { count } </div> ) } export default App
更新函数
import { useState } from "react" function App () { const [count, setCount] = useState(0) const handleClick = () => { //setCount(count + 1) // 0 + 1 找的是当前作用域下的快照 // setCount((c) => c + 1) // 0 + 1 c和快照没关系 //setCount(count + 1) // 0 + 1 //setCount(count + 1) // 0 + 1 //setCount(count + 1) // 0 + 1 // setCount((c) => c + 1) // 1 + 1 // setCount((c) => c + 1) // 2 + 1 // setTimeout(()=>{ // console.log( count ) // 0 // }, 3000) setCount(count + 1) // setCount((c) => count + 1) } return ( <div> hello App <button onClick={handleClick}>点击</button> { count } </div> ) } export default App