三、业务场景与案例
(一)父子组件通信案例
在React中,父子组件之间可以通过多种方式进行通信。父组件可以通过props向子组件传递数据,子组件可以通过回调函数或事件冒泡向父组件传递信息。
下面是一个简单的例子,展示了如何使用props和回调函数实现父子组件之间的通信:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { message: "" };
}
handleMessage = (message) => {
this.setState({ message });
};
render() {
return (
<div>
<Child onMessage={this.handleMessage} />
<p>Message from child: {this.state.message}</p>
</div>
);
}
}
const Child = ({ onMessage }) => {
const handleClick = () => {
onMessage("Hello from child!");
};
return <button onClick={handleClick}>Send Message</button>;
};
复制代码
在这个例子中,Parent 组件通过 props 向 Child 组件传递了一个回调函数 handleMessage。当 Child 组件中的按钮被点击时,它会调用这个回调函数并传递一个消息给 Parent 组件。然后,Parent 组件会更新它的状态并显示来自 Child 组件的消息。
(二)组件间共享信息_Reducer & Context
在React中,可以使用Reducer和Context来拓展应用。Reducer可以整合组件的状态更新逻辑,而Context可以将信息深入传递给其他组件。你可以组合使用它们来共同管理一个复杂页面的状态。
这是一个使用Context和Reducer的例子,演示了如何在React中使用它们来共享状态。在这个例子中,我们创建了一个ProfileContext,并使用useReducer来管理状态。还定义了一个reloadProfile函数来异步获取数据,并在组件中使用useEffect来调用它。最后,将状态和dispatch函数传递给ProfileContext.Provider,以便在组件树中的其他组件中访问它们。
import React, { useCallback } from 'react'
const ProfileContext = React.createContext()
const initialState = {
data: false
}
let reducer = (state, action) => {
switch (action.type) {
case 'unload':
return initialState
case 'profileReady':
return { data: action.payload }
}
}
const reloadProfile = async () => {
try {
let profileData = await fetch('/profile')
profileData = await profileData.json()
return profileData
} catch (error) {
console.log(error)
}
}
function ProfileContextProvider(props) {
let [profile, profileR] = React.useReducer(reducer, initialState)
const customDispatch = useCallback(async (action) => {
switch (action.type) {
case 'reload': {
const profileData = await reloadProfile()
profileR({ type: 'profileReady', payload: profileData })
break
}
default:
// Not a special case
profileR(action)
}
}, [])
return (
<ProfileContext.Provider value={{ profile, customDispatch }}>
{props.children}
</ProfileContext.Provider>
)
}
export { ProfileContext, ProfileContextProvider }
复制代码
(三)组件间共享信息_redux
另一种在React中实现组件之间信息共享的方法是使用Redux。Redux是一个独立的状态管理库,它可以与React一起使用。在Redux中,我们可以定义一个全局的store来存储应用程序的状态。然后,定义action来描述状态的变化,并使用reducer函数来处理这些action并更新状态。
下面是一个简单的例子,它演示了如何在React中使用Redux来共享状态:
import { createStore } from 'redux'
// 1. 定义初始化的state
const initState = {
num: 0
}
// 2. 定义action
function add() {
return { type: 'INCREMENT' }
}
function dec() {
return { type: 'DECREMENT' }
}
// 3. 编写reducer函数
function reducer(state = initState, action) {
switch (action.type) {
case 'INCREMENT':
return { num: state.num + 1 }
case 'DECREMENT':
return { num: state.num - 1 }
default:
return state
}
}
// 4. 创建store
const store = createStore(reducer)
// 5. 使用dispatch触发action
store.dispatch(add())
store.dispatch(add())
store.dispatch(dec())
复制代码
(四)你不知道的冒泡_Portal
在React中,我们可以使用Portal来将子节点渲染到父组件DOM层次结构之外的DOM节点。这可以通过调用ReactDOM.createPortal(child, container)来实现。其中,child是要渲染的React元素,而container是要将子节点插入到的DOM元素。
export default function App() {
const [isShow, setIsShow] = useState(false);
function click(e) {
console.info("e", e);
setIsShow(!isShow);
}
return (
<div
style={{ backgroundColor: "#a00", width: `200px`, height: `100px` }}
onClick={click}
>
{isShow && (
<Modal>
<span>zhangsan</span>
</Modal>
)}
</div>
);
}
复制代码
虽然Portal可以将子节点渲染到父组件DOM层次结构之外的DOM节点,但是它仍然遵循React的事件冒泡机制。也就是说,如果你在Portal中触发了一个事件,它会沿着React组件树向上冒泡,而不是沿着实际渲染的DOM元素结构。