react开发我们会把页面分为一个个组件,组件是独立而且可复用的重复代码片段。具体来说组件可以是一个按钮,一个输入框。react组件有两种定义方法,一种是函数组件,一种是类组件。我们这里说一下函数组件之间父子之间如何传递props参数,如果通过ref来获取真实DOM元素,如何通过设置state这个react变量去动态展示页面中的数据。
1.props
import React from 'react'
import LogItem from './LogItem'
import './Log.css'
export default function Logs() {//模拟一组从服务器加载的数据const logsData = [{id: "001",data: new Date(2021, 9, 20, 19, 0),title: '学习九阳神功',time: 30},{id: "002",data: new Date(2021, 4, 20, 19, 0),title: '学习我我我功',time: 20},{id: "003",data: new Date(2021, 5, 20, 19, 0),title: '学习你你神功',time: 10},{id: "004",data: new Date(2022, 1, 20, 19, 0),title: '学习九大大滴神功',time: 34}]return (// 如果组件中的数据全部写死会导致组件无法动态设置//希望组件数据可以由外部设置 在组件间父组件可以通过props给子组件传递数据<div className='logs'>{/* 在父组件给子组件设置属性在函数组件中可以通过参数来保存 */}{logsData.map((item) => {return (<LogItem key={item.id} data={item.data} title={item.title} time={item.time} />// <LogItem {...item} />)})}</div>)
}
这里我们在组件中定义了一个数组对象,作为服务器返回的json数据。我们想要一个列表去展示这些数据,每个列表都是相同的,所以我们需要一个子组件展示内容,父组件遍历展示子组件就可以了。我们需要把数据传给子组件,通过props传递方法就是之间传,通过key=value这种方式直接传递,key不会作为参数,会作为内部特殊属性保留。然后传递过去之后子组件去获取然后展示。
import React from 'react'
import MyDate from './MyDate'
import './LogItem.css'
export default function LogItem(props) {// console.log(props);// console.log(props.data);return (//函数组件的行参定义一个props props指向一个对象 包含父组件传递所有参数<div className="item"><MyDate data={props.data} /><div className="content"><h2 className='title'>{props.title}</h2><div className="time">{props.time}</div></div></div>)
}
函数组件直接在参数里面props接收就可以了。输出的props就是传过来的那些props参数。然后{}里面写表达式就可以动态展示了。props是父组件给子组件传递的方式。
2.ref
我们在开发用react框架开发时,如果需要操作真实DOM,我们可以通过DOM对象(document)去操作DOM,也可以直接从react获取DOM对象,首先用钩子函数useRef()去创建一个存储DOM对象的容器,其实就是一个非常普通的对象,里面有一个current属性仅此而已。
import React, { useRef } from 'react'
import './App.css'
import { useState } from 'react'
let temp
export default function App() {console.log('函数执行了');const h1Ref = useRef()//创建一个容器// const h1Ref = { current: undefined }console.log(temp === h1Ref);temp = h1Ref//这里永远不相等因为每次都是生成新对象//直接用这种创建一个有current属性的对象也可以console.log(h1Ref);const clickHandler = () => {// const header = document.getElementById('header')// alert(header)// header.innerHTML = '哈哈'//原生DOM操作DOM元素h1Ref.current.innerHTML = 'hah'}return (<div className='app'><h1>{a}</h1><h1 id='header' ref={h1Ref}>为上标题</h1><button onClick={add}>加</button><h1>{user.name}-----{user.age}</h1><button onClick={go}>2</button><button onClick={clickHandler}>点完</button></div>)
}
比如我们希望用按钮去操作h1标签里面的文本改变,用document操作就需要设置id,然后通过id获取元素对象赋值给header,然后调用header.innerText=‘haha’ ,但是我们在react尽量避免使用dom因为会脱离react掌控。我们这里用钩子函数去定义一个容器h1Ref然后给我们想要操作的DOM一个ref属性值是容器,那么就存到了这个容器对象的current里面,控制台可以看,而且只是一个简单的js对象。我们可以直接定义一个对象去代替,属性就是current。然后直接h1Ref.current.innerHTML='hha'操作h1的文本内容,只不过需要注意的是useRef()创建的容器只会生成一次,如果直接创建对象的话每次重新渲染都需要重新生成一个新的对象。所以如果我们需要保持一个不变的对象或者值,多次渲染不丢失重置就可以用uesRef比如我们关闭定时器用到的id
function MyComponent() {const timerRef = useRef(null); // 创建一个持久的容器对象useEffect(() => {timerRef.current = setInterval(() => console.log('hi'), 1000);}, []);return <button onClick={() => clearInterval(timerRef.current)}>停止</button>;
}
3.state
当我们想要设置一个变量,而且这个变量动态的展示到页面上面,我们就需要去用钩子函数useState()去创建一个数组,前面是我们的变量,后面是一个函数,调用之后可以用回调函数去更新我们的变量。
import React, { useRef } from 'react'
import './App.css'
import { useState } from 'react'
let temp
export default function App() {console.log('函数执行了');console.log(h1Ref);// let a =1let [a, setA] = useState(2)console.log(useState());//输出的是一个数组前面是初始值后面是函数const result = useState(1)console.log(result);let fn = result[1]console.log('fn', fn)const [user, setUser] = useState({ name: 'sun', age: 11 })//点击加数字增加 点击减数字减少const add = () => {// a++// setA(a++)setA((preState) => {return preState + 1})}const go = () => {// user.name = 'gou'// setUser(user) //不会重新渲染因为修改的是原对象// const newUser = Object.assign({}, user)// newUser.name = 'gou'// setUser(newUser)//这个方法可以因为浅复制给一个新对象复制,地址是改变的// setUser({ name: 'zhu', age: 19 })setUser({ ...user, name: 'gou' })}return (<div className='app'><h1>{a}</h1><h1 id='header' ref={h1Ref}>为上标题</h1><button onClick={add}>加</button><h1>{user.name}-----{user.age}</h1><button onClick={go}>2</button><button onClick={clickHandler}>点完</button></div>)
}
我们如果直接let a = 1 然后我们点击按钮其实a改变了,但是页面a不会改变,因为没有重新渲染页面。所以a++执行成功但是页面a没有变化,这时候我们用我们的钩子函数useState()并且用数组结构的方法去设置a。然后我们调用setA这个方法,里面设置一个回调函数,preState是当前的变量a,然后返回更新后的新的变量a。然后重新调渲染页面。
state特点。1.state是一个被react管理的变量 通过setState()修改变量的值会触发重新渲染,重新调用一个render(),然后重新diff比较之后更新然后用DOM转化虚拟DOM对象为真实DOM,只有state发生变化才会重新渲染。state是一个对象 修改时使用新的对象替换已有对象,直接修改原有对象 不会生效因为地址没变,当通过setState去修改一个state时不表示修改当前state,修改的是组件下一次渲染的state值。
2.setState()会触发组件重新渲染 它是异步的,会排队让同步代码执行完以后再执行重新渲染,所以当调用setState()需要用到旧state值一定要注意 有可能出现计算错误的情况,为了避免这种情况可以传递回调函数的形式 箭头函数参数为当前最新的state