摘要
本篇主要是react基础篇。
- 受控表单绑定[表单双向绑定的处理]
- 获取dom方式
- 组件通信
- 父传子-props
- 子传父-调方法
- 兄弟之间- 先子传父,再父传子
- 跨层传递-context
受控表单绑定
也就是vue里对应的的一个概念:表单数据的双向绑定。
概念: 使用React组件的状态(useState) 控制 表单的状态。
这里有2个状态值,一个是react内部的状态值,一个是表单用户录入的数据值。
双向:
-
React[state] ---> [value] 把state值绑定到input的value上
-
React[state] <--- [value] 把input用户输入的值告知(set)给React的state
具体怎么实现呢:
分2步:
- 准备一个React状态值
const [value,setValue] = useState('')
- 通过value属性绑定状态,通过onChange属性绑定状态同步的函数
双向全流程体现在2条线:
-
value = {value},把state值绑定到input的value上
-
setValue(e.target.value),把input用户输入的值告知(set)给React的state
<input type="text" value={value} onChange={(e)=> setValue(e.target.value)}
获取dom元素
通过useRef钩子函数。分2步:
- 使用useRef 创建ref对象,并绑定到dom标签身上。
const inputRef = useRef(null)
<input type="text" ref={inputRef}/>
- 在Dom可用时,通过
inputRef.current
拿到DOM对象。
console.dir(inputRef.current)
//ps:dir语句打印的是对象的所有属性和方法
注意: 这个 Dom可用时
的理解,是当前组件渲染完毕,也就是dom生成之后。比如:点击事件。这个时候肯定是渲染完了。
组件通信
概念:组件之间的数据传递。根据组件嵌套关系不同,通信方式也各不相同。
父传子
实现步骤:
-
父组件传递数据,在子组件标签上绑定一个属性。[发生在父组件中,子组件标签身上]
-
子组件接收数据,子组件通过props参数接收数据。[发生在子组件中 ]
通过props
代码实现:
一个简单的无通信的父子组件嵌套
function Father(){
return(
<div>
<Son/>
</div>
)
}
function Son(){
return <div> I am son </div>
}
此时,如果想把 Father里的一个数据 version
传递给Son。
function Father(){
let ver = '1.1.0'
return(
<div>
<Son version={ver}/>//1. 传递处,子标签身上自定义一个属性version.
</div>
)
}
function Son(props){//2. 接收处,加一入参props来收数据,具体属性名和定义处保持一致即可。
return <div> I am son,版本 {props.version} </div>
}
props可传递的数据类型
react里props非常灵活,可以传递任意类型:数字、字符串、布尔值、对象、数组、函数、jsx(dom片段)
function Father(){
let ver = '1.1.0'
return(
<div>
<Son version={ver}
age={20}
isFlag={false}
arrList={['数学','语文']}
obj={{key1:val1}}
cb={()=>console.log(1)}
jsx={<div>I am dom</div>}
/>//1. 传递处,子标签身上自定义
</div>
)
}
function Son(props){//2. 接收处,加一入参props来收数据,具体属性名和定义处保持一致即可。
console.log(props)
return <div> {props.version} </div>
}
props是只读对象
子组件里是不可以对props进行修改的,它是父组件的数据,所以只有父组件有权利改。
遵循 谁的数据,谁有权更改!
特殊的props-children
什么场景会用到呢?
当我们把内容嵌套在子组件标签中时,父组件会自动在名为children的prop属性中接收该内容。
function Father(){
return(
<div>
<Son> <span> 我是嵌套到自定义标签Son里的子标签 </span></Son>
</div>
)
}
function Son(props){
return <div> I am son {props.children}</div>
}
也就是说: 自定义标签里写东西,也是可以识别的,react把它识别到一个叫children的属性里了。
子传父
核心: 1、父通过props把一个自己的函数传递给子,2、然后在子中调用父组件中的函数并传递参数。
import {useState} from 'react'
function Father(){
const [msg,setMsg] = useState('')
const getMsg = (msg)=>{
setMsg(msg)
}
return(
<div>
<Son onGetMsg={getMsg}/>
来自son传递来的消息:{msg}
</div>
)
}
function Son(props){
const msg = '我是子里要传给父的数据源'
return <button onClick={()=> props.onGetMsg(msg)}>send</button>
}
兄弟组件传值
核心:将子传父,父传子 进行组合。也就是 利用 "状态提升" 机制!
父组件:App,子组件1:A ,子组件2:B
如果想实现A的值传递给B,我们可以先:A->App
,然后再 App->B
。
传值前,3个组件代码如下:
A:
function A(){
const msg = '我是要传递的源数据'
return(
<div>
我是A组件
<button>send</button>
</div>
)
}
B:
function B(){
return(
<div>
我是B组件
</div>
)
}
App:
function App(){
return(
<div>
我是App组件
<A></A>
<B></B>
</div>
)
}
传值处理改造:
A:
function A(props){//2:
const msg = '我是要传递的源数据'
return(
<div>
我是A组件
<button onClick={()=>props.onGetMsg(msg)}>send</button>//2:
</div>
)
}
B:
function B({msg}){//解构//4:
return(
<div>
我是B组件
传来的值:{msg}//4:
</div>
)
}
App:
function App(){
// 这里用useState包裹成状态量,就是为了下游的B里具有响应性,A里的值发生变化,B中视图也能同步更新!
const [msg,setMsg] = useState('')//1:
const getMsg = (msg)=>{//1:
setMsg(msg)
}
return(
<div>
我是App组件
<A onGetMsg={getMsg}></A>//1:
<B msg={msg}></B>//3:
</div>
)
}
1: 在父组件里,通过给A组件灌入一个props:onGetMsg 属性把 方法getMsg传进去。 2: 在A组件里,我们要用props参数接收 下发给我的方法属性onGetMsg,然后在触发角绑定方法并调用,同时把要传递的msg作为实参传递过去。 3: 在父组件里,已经拿到A传递的msg后,响应式状态量msg有值后,可以通过给B组件灌入一个props:msg 属性把 值传进去。 4: 在B组件里,我们要用props参数接收 下发给我的属性msg,然后在页面里使用,显示出来。
至此,一个完整的传递过程完成了。代码里按照处理顺序标记了序号1/2/3/4
跨层组件传值
可能是爷孙,只要是层级嵌套关系的就可以使用。
主要3步:
1. 使用 createContext 方法创建一个上下文对象Ctx
2. 在顶层组件中通过 Ctx.Provider组件 提供数据
3. 在底层组件中通过useContext钩子函数获取并使用数据
案例:
App > A > B, App里嵌套A,A里嵌套B,想把App里的数据msg传递给B.
传递前组件代码:
function A(){
return(
<div>
我是A组件
<B/>
</div>
)
}
function B(){
return(
<div>
我是B组件
</div>
)
}
function App(){
const msg = '我是要传递的源数据'
return(
<div>
我是App组件
<A></A>
</div>
)
}
传值处理改造:
import {createContext} from 'react'
const MsgContext = createContext()//1: 创建Ctx上下文,一般命名:大驼峰,消息名+Context组合
function A(){
return(
<div>
我是A组件
<B/>
</div>
)
}
function B(){
const msg = useContext(MsgContext)//3:在底层消费数据组件里利用hooks函数useContext进行接收数据(之前创建的Ctx-> MsgContext)
return(
<div>
我是B组件
使用接收到的数据:{msg}
使用接收到的数据:{msg}
</div>
)
}
function App(){
const msg = '我是要传递的源数据'
return(
<div>
//2.在底层传送数据组件里,使用Ctx.Provider组件标签包裹住要所有子节点,尤其是A(因为A里嵌套B),同时通过value属性把值传入。
<MsgContext.Provider value={msg}>
我是App组件
<A></A>
</MsgContext.Provider>
</div>
)
}