React 组件通信

React组件通信方式总结:1)父传子通过props单向传递数据,子组件不能直接修改;2)子传父通过回调函数实现数据传递;3)兄弟组件通过状态提升到共同父组件实现通信;4)跨层组件可使用Context机制,通过Provider提供数据,useContext获取;5)复杂应用推荐Redux集中状态管理,通过createSlice创建reducer,Provider注入store,useSelector和useDispatch操作状态。Redux Toolkit简化了Redux使用流程,支持同步/异步操作。

  1. 父传子
    父组件通过 props 传递数据给子组件,子组件通过 props 接收数据。
    props 可以传递任意类型的数据,包括字符串、布尔值、函数、对象、数组、JSX 等。
javascript 复制代码
// 父组件
function Parent() {
  const [value, setValue] = useState("父组件传递的数据");
  return (
    <div>
      <Child value={value} />
    </div>
  );
}

// 子组件
function Child(props: { value: string }) {
  return <div>{props.value}</div>;
}

props 是只读的,不能直接修改,父组件的数据只能由父组件修改。

props children

javascript 复制代码
// 父组件 标签嵌套
<Son>
  <span>我是span标签</span>
</Son>;

// 子组件 通过props.children渲染在页面中
function Son(props: { children: React.ReactNode }) {
  return (
    <div>
      <h1>我是子组件</h1>
      <hr />
      {props.children}
    </div>
  );
}
  1. 子传父

子组件通过 props 传递数据给父组件,父组件通过 props 接收数据,并传递给子组件。

javascript 复制代码
// 父组件
function Parent() {
  const [value, setValue] = useState("");
  const handleChildChange = (value: string) => {
    setValue(value);
  };
  return (
    <div>
      <Child onChange={handleChildChange} />
      <p>{value}</p>
    </div>
  );
}

// 子组件
function Child(props: { onChange: (value: string) => void }) {
  const [value, setValue] = useState("");
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
    props.onChange(e.target.value);
  };
  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
    </div>
  );
}
  1. 兄弟组件

使用状态提升实现兄弟组件通信,即通过共同的父组件传递

javascript 复制代码
// 父组件
function Parent() {
  const [value, setValue] = useState("");
  const handleChildChange = (value: string) => {
    setValue(value);
  };
  return (
    <div>
      <Child1 onChange={handleChildChange} />
      <Child2 value={value} />
    </div>
  );
}

// 子组件1
function Child1(props: { onChange: (value: string) => void }) {
  const [value, setValue] = useState("");
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
    props.onChange(e.target.value);
  };
  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
    </div>
  );
}

// 子组件2
function Child2(props: { value: string }) {
  return (
    <div>
      <p>{props.value}</p>
    </div>
  );
}
  1. 跨层组件通信------Context 机制
javascript 复制代码
// 1. 创建Context
const MyContext = createContext();
// 2. 顶层组件通过Provider组件提供数据
function Parent() {
  const [value, setValue] = useState("");
  const handleChildChange = (value: string) => {
    setValue(value);
  };
  return (
    <MyContext.Provider value={value}>
      <Child1 onChange={handleChildChange} />
      <Child2 />
    </MyContext.Provider>
  );
}

// 3. 子组件通过useContext钩子获取数据
function Child2() {
  const value = useContext(MyContext);
  return (
    <div>
      <p>{value}</p>
    </div>
  );
}
  1. 跨层组件通信------Redux 机制 (集中状态管理工具)
javascript 复制代码
// 1. 安装
// Redux Toolkit:是一套工具集,用于简化 Redux 的书写方式
// react-redux:链接React和Redux的中间件
npm i @reduxjs/toolkit react-redux

// 2. 创建slice store/modules/counterStore.js
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";

const counterSlice = createSlice({
  name: "counter", // 命名空间
  // 初始化状态
  initialState: {
    count: 0
  },
  // 定义修改状态的方法 同步方法 支持直接修改
  reducers: {
    increment(state) {
      state.count ++;
    },
    decrement(state) {
      state.count --;
    },
    // 支持传递参数 传递的参数会作为action.payload payload:固定的属性名
    addToNum(state,action){
      state.count+= action.payload
    },
  },
});

const channelSlice = createSlice({
  name: "channel",
  initialState: {
    channelList: []
  },
  reducers: {
    // 获取异步数据
    setChannel(state,action){
      state.channelList = action.payload
    }
  }
})

// 解构actioncCreater函数
const { increment, decrement,addToNum } = counterSlice.actions;
const { setChannel } = channelSlice.actions;

// 发起异步请求
const getChannelList = () =>  {
  return async (dispatch)=>{
    const res = await axios.get("http://localhost:3000/channel");
    dispatch(setChannel(res.data))
  }
}
const countReducer = counterSlice.reducer;
const channelReducer = channelSlice.reducer;
// 导出方法
export { increment, decrement, addToNum, getChannelList };
export default countReducer;
export default channelReducer;

// 3. 创建store store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";
import channelReducer from "./channelSlice";

const store = configureStore({
  reducer: {
    counter: counterReducer,
    channel: channelReducer,
  },
});

export default store;

// 4. 在顶层组件中提供store App.js
import { Provider } from "react-redux";
import store from "./store";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>
);

// 5. 在子组件中获取store中的数据 useSelector:映射store中的数据 useDispatch:分发action
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement, addToNum, getChannelList } from "./counterSlice";

function Counter() {
  // 映射store中的数据
  const count = useSelector((state) => state.counter);
  const list= useSelector((state) => state.channel);
  const dispatch = useDispatch();

  // 触发请求
  useEffect(()=>{
    dispatch(getChannelList())
  },[dispatch])

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
      {/* 传参 */}
      <button onClick={() => dispatch(addToNum(10))}>+10</button>
      {/* 数据列表 */}
      <ul>
        {list.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}
相关推荐
mldong3 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排4 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60614 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角5 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!5 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰6 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi7 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen8 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马8 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒9 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端