前言:Hello,我是一个野生的React玩家,在学习过程中发现学过的很容易忘记,在这里记录一下,还希望能认识一些React小伙伴,学习的路上太孤单啦。
正文:那么开始基础的组件之间的通讯,是我掌握的三种方式
- props
- context 基于createContext
- 发布订阅
- 第一个是最普通的props传值,并传递改变自身状态的函数来实现子组件修改父组件状态。针对父孙组件之间则是逐级向下传递props,从头传到尾。针对兄弟组件则是通过父来建立联系(缺点是针对父孙和兄弟组件通讯代码看上去比较麻烦)
函数式组件 通过子组件修改父组件的count值,将count初始值和修改函数传入子组件
// Parent.js 父组件
import React from 'react';
import {useState} from 'react';
import Children from './children';
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<span>{count}</span>
<Children count={count} setCount={setCount}></Children>
</div>
)
}
export default Parent;
函数式组件 子组件通过props获取count初始值和count修改函数并使用
// Children.js 子组件
import React from 'react';
function Children(props) {
function addCount() {
props.setCount(props.count + 1);
}
return (
<div>
<button onClick={addCount}>add count</button>
{/* other component example <Other {...props}> */}
</div>
)
}
export default Children;
- 第二种方式通过Context来实现数据共享(优点是代码整洁,一步到位)
先创建对应的Context
// context.js
import {createContext} from 'react';
export const TestContext = createContext({});
函数式组件 将父组件包含在Context内,共享状态count并共享count的修改函数setCount
// Parent.js 父组件
import React from 'react';
import {useState} from 'react';
import Children from './children';
import {TestContext} from './Context';
function Parent() {
const [count, setCount] = useState(0);
return (
<TestContext.Provider
value={{
count: count,
setCount: setCount
}}
>
<div>
<span>{count}</span>
<Children></Children>
</div>
</TestContext.Provider>
)
}
export default Parent;
函数式组件 子组件,包括任意该父组件下的子组件都可以这样来访问和修改count
// Children.js 子组件
import React from 'react';
import {useContext} from 'react';
import {TestContext} from './Context';
function Children(props) {
const {count, setCount} = useContext(TestContext);
function addCount() {
setCount(count + 1);
}
return (
<div>
<button onClick={addCount}>add count</button>
</div>
)
}
export default Children;
- 第三种发布订阅模式(优点不必对父组件做什么封装,可以在任意位置1对1互联。缺点组件被多次使用即多次订阅会被一次发布全部触发,相同订阅的会被影响)
创建eventProxy.js用于实现发布订阅,即在使用on函数时往map里注册一个订阅事件,该事件可以有多个订阅函数。使用emit函数发布一个事件来触发订阅的函数
const eventProxy = {
map: {}, // 映射关系
on: function(sign, fn) { // 订阅
var map = this.map;
if(!map[sign]) {
map[sign] = [];
}
map[sign].push(fn);
},
emit: function(sign, backData) { // 发布
var map = this.map;
if(map[sign]) {
map[sign].forEach(element => {
element(backData);
});
} else {
throw "没有地方订阅";
}
}
}
export default eventProxy;
函数式组件 父组件订阅一个事件,事件名为input,传入回调事件并接收返回参数,这里传入了count值给子组件
import React from 'react';
import {useState} from 'react';
import Children from './children';
import eventProxy from './eventProxy';
function Parent() {
const [count, setCount] = useState(0);
eventProxy.on("input", (val) => {
setCount(val)
})
return (
<div>
<span>{count}</span>
<Children count={count}></Children>
</div>
)
}
export default Parent;
函数式组件 子组件注册发布事件,事件名对应父组件注册的input事件,并传入回调参数
import React from 'react';
import eventProxy from './eventProxy';
function Children(props) {
function addCount() {
eventProxy.emit("input", props.count + 1);
}
return (
<div>
<button onClick={addCount}>add count</button>
</div>
)
}
export default Children;
总结:不知道还有没有别的方式,先记录这三种方法,感觉第三种还是挺坑的,同一个组件多次调用会互相影响(如select组件用这种方式控制选中赋值,当注册多个select的时候,一经发布所有的都会响应,结果所有select都变成一样的值了),不知道是否有解决的办法,非常期待留言,希望各位大佬别嫌弃。