文件结构
- App.js
// import StateHook from './components/StateHook'; // import EffectHook from './components/EffectHook'; // import LayoutEffectHook from './components/LayoutEffectHook'; // import MemoHook from './components/MemoHook'; // import CallbackHook from './components/CallbackHook'; // import ReactMemo from './components/ReactMemo'; // import RefHook from './components/RefHook'; // import ForwardRefHook from './components/ForwardRefHook'; // import ImperativeHandleHook from './components/ImperativeHandleHook'; // import ContextHook from "./components/ContextHook"; // import ReducerHook from "./components/ReducerHook"; // import ObjectDemo from "./components/ObjectDemo"; // import FromParentToSon from './components/FromParentToSon'; // import FromSonToParent from './components/FromSonToParent'; // import SkipLevel from './components/SkipLevel'; // import BrotherComponent from './components/BrotherComponent'; import PubSub from './components/PubSub'; const App = () => { return ( <div> {/* <StateHook></StateHook> */} {/* <EffectHook></EffectHook> */} {/* <LayoutEffectHook></LayoutEffectHook> */} {/* <MemoHook></MemoHook> */} {/* <CallbackHook></CallbackHook> */} {/* <ReactMemo></ReactMemo> */} {/* <RefHook></RefHook> */} {/* <ForwardRefHook></ForwardRefHook> */} {/* <ImperativeHandleHook></ImperativeHandleHook> */} {/* <ContextHook></ContextHook> */} {/* <ReducerHook></ReducerHook> */} {/* <ObjectDemo></ObjectDemo> */} {/* <FromParentToSon></FromParentToSon> */} {/* <FromSonToParent></FromSonToParent> */} {/* <SkipLevel></SkipLevel> */} {/* <BrotherComponent></BrotherComponent> */} <PubSub></PubSub> </div> ); }; export default App;
父子组件通信
父传子
主要通过属性传递的方式:
- 使用
import { useState } from "react";
const FromParentToSon = () => {
const [obj, setObj] = useState({ name: "w", age: 18 });
const incrementAge = () => {
setObj((prev) => {
return { ...prev, age: prev.age + 1 };
});
};
return (
<div>
<h1>
From Father to Son--name:{obj.name}--age:{obj.age}
</h1>
<button onClick={incrementAge}>age+</button>
<Child age={obj.age} />
</div>
);
};
const Child = (props) => {
let { age } = props;
return (
<div>
<h1>Son--age{age}</h1>
</div>
);
};
export default FromParentToSon;
子传父
通过调用父组件传递过来的方法,调用方法将参数传递出去
- 使用
import { useState } from "react"; const FromSonToParent = () => { const [obj, setNum] = useState({ num: 0 }); const handleClick = (age) => { setNum((prev) => { return { ...prev, num: age, }; }); }; return ( <div> <h6>parent--age:{obj.num}</h6> <Child handleClick={handleClick} /> </div> ); }; const Child = (props) => { const { handleClick } = props; const [age, setAge] = useState(18); const handleDataToParent = () => { handleClick(age); }; return ( <div> <button onClick={handleDataToParent}>点我给父传数据</button> <button onClick={() => setAge(age + 1)}>点我改变年龄</button> <h6>child--age:{age}</h6> </div> ); }; export default FromSonToParent;
跨级组件
- 介绍
对于跨级组件来说,可以采用层层传递属性的方式来实现组件之间的通信,但是当层级嵌套关系较深的时候,层层传递是比较繁琐且容易出错的,所以这里利用context来实现组件通信。组件层级关系App>SkipLevel>Child1>Child2>Child3。
- 目录结构
- 使用
- userUseContext.js
import React from "react";
let UserContext = React.createContext();
export default UserContext;
- SkipLevel/index.jsx
import React, { useState } from "react";
import Child1 from "./components/Child1";
import userUseContext from "./userUseContext";
const SkipLevel = () => {
let object = {
name: "w",
age: 25,
};
let [obj, setObj] = useState(object);
return (
<div>
<h6>parent--age{obj.age}</h6>
<button onClick={() => setObj({ ...obj, age: ++obj.age })}>age+</button>
<userUseContext.Provider value={obj.age}>
<Child1></Child1>
</userUseContext.Provider>
</div>
);
};
export default SkipLevel;
- SkipLevel\components\Child1\index.jsx
import Child2 from "../Child2";
const Child1 = () => {
return (
<div>
<Child2></Child2>
</div>
);
};
export default Child1;
- SkipLevel\components\Child2\index.jsx
import Child3 from "../Child3";
const Child2 = () => {
return (
<div>
<Child3></Child3>
</div>
);
};
export default Child2;
- SkipLevel\components\Child3\index.jsx
import userUseContext from "../../userUseContext";
import { useContext } from "react";
const Child3 = () => {
let user = useContext(userUseContext);
console.log("user", user);
return (
<div>
<h1>Child3</h1>
<h2>user.age:{user}</h2>
</div>
)
};
export default Child3;
兄弟组件
- 介绍
react的数据流是自顶向下的,无法通过react直接进行兄弟组件通信,通常是子组件向父组件传递数据,再有父组件告知另一个子组件。组件层级关BrotherComponent>Child1、Child2,组件BrotherComponent调用了组件Child1和组件Child2,组件Child1和Child2是兄弟组件。
- 目录结构
- 使用
- BrotherComponent\index.jsx
import { useState } from "react";
import Child1 from "./components/Child1";
import Child2 from "./components/Child2";
const BrotherComponent = () => {
let object = {
num:0,
name:"w"
}
const [obj,setObj] = useState(object)
const IncrementAge = (value) => {
setObj({...obj,num:obj.num+Number(value)})
}
return (
<div>
<h6>BrotherComponent--{obj.num}--{obj.name}</h6>
<Child1 IncrementAge={IncrementAge}></Child1>
<Child2 age={obj.num}></Child2>
</div>
)
}
export default BrotherComponent;
- BrotherComponent\components\Child1\index.jsx
const Child1 = (props) => {
let {IncrementAge} = props;
return (
<div>
<h6>Child1</h6>
<select onChange={(e)=>IncrementAge(e.target.value)}>
<option value="1">+1</option>
<option value="2">+2</option>
<option value="3">+3</option>
</select>
</div>
)
}
export default Child1;
- BrotherComponent\components\Child2\index.jsx
const Child2 = (props) => {
let {age} = props;
return (
<div>
<h6>Child2--{age}</h6>
</div>
)
}
export default Child2;
任意组件之间
订阅发布模式
- 首先,我们需要安装PubSub库:
npm install pubsub-js
- 然后,让我们来看一个示例,展示如何在React应用中使用PubSub进行组件间的通信。
- 目录结构
- 使用
- PubSub\index.jsx
import Child1 from "./components/Child1";
import Child4 from "./components/Child4";
const PubSub = ()=> {
return (
<div>
<h1>PubSub</h1>
<Child1></Child1>
<Child4></Child4>
</div>
)
}
export default PubSub;
- PubSub\components\Child1\index.jsx
import Child2 from '../Child2';
const Child1 = ()=> {
return (
<div>
<h1>Child1</h1>
<Child2></Child2>
</div>
)
}
export default Child1;
- PubSub\components\Child2\index.jsx
import Child3 from '../Child3';
const Child2 = ()=> {
return (
<div>
<h1>Child2</h1>
<Child3></Child3>
</div>
)
}
export default Child2;
- PubSub\components\Child3\index.jsx 发布消息的组件
import { useState } from "react";
import pubsub from "pubsub-js";
const Child3 = () => {
let object = {
name: "Child3",
age: 30,
};
let [obj, setObj] = useState(object);
const handleClick = () => {
pubsub.publish("sendDateToBrother5", obj.age);
};
const IncreaseAge = () => {
setObj((prev) => {
return { ...prev, age: prev.age + 1 };
});
};
return (
<div>
<h1>
Child3--age{obj.age}--name{obj.name}
</h1>
<button onClick={IncreaseAge}>Age+</button>
<button onClick={handleClick}>点我向五弟发送数据</button>
</div>
);
};
export default Child3;
- PubSub\components\Child4\index.jsx
import Child5 from '../Child5';
const Child4 = ()=> {
return (
<div>
<h1>Child4</h1>
<Child5></Child5>
</div>
)
}
export default Child4;
- PubSub\components\Child5\index.jsx 订阅消息的组件
import pubsub from "pubsub-js";
import { useEffect, useState } from "react";
const Child5 = () => {
let [count, setCount] = useState(0);
useEffect(() => {
let test = pubsub.subscribe("sendDateToBrother5", (_, b) => {
console.log("b", b);
});
console.log("test", test);
return () => {
pubsub.unsubscribe(test);
console.log(777);
};
},[]);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<h1>Child5--count{count}</h1>
<button onClick={handleClick}>点击+1</button>
</div>
);
};
export default Child5;
通过这种消息订阅发布的模式,我们可以实现组件之间的解耦,使得它们能够独立地进行通信,而不需要直接引用彼此。这样的设计模式有助于提高代码的可维护性和可扩展性,使得应用程序更易于理解和维护。