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 =1
let [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