【问题标题】:Can I change a parent components State by passing the setState function to the Link Component?我可以通过将 setState 函数传递给链接组件来更改父组件状态吗?
【发布时间】:2023-02-10 05:54:56
【问题描述】:

我有一个简单的链接设置,可以转到列表中特定项目的详细信息部分。 但是,当我在 Link 组件中传递 setter 函数时,它会出错,因为我的所有其他状态变量都是 Null。

代码如下所示:

`<链接 to={"device" + "/" + comp.hostname} 状态={{ 时间:时间, 日期:日期, 当前工作:当前工作, setCurrentJobs:setCurrentJobs }}

`

我的问题是,当我传递“setCurrentJobs”变量时,链接将我带到下一页,但显示时间未定义。

我相信我在链接引用的组件内部设置了 useLocation:

const location = useLocation()
const time = location.state.time
const date = location.state.date
const currentJobs = location.state.currentJobs
const setCurrentJobs = location.state.setCurrentJobs

如果我不传递 setter 函数,代码就可以正常工作。是不是Component不允许传递函数?

【问题讨论】:

    标签: reactjs components state setstate


    【解决方案1】:

    将 setter 放入另一个状态是有问题的。考虑这种简单地使用React Context 来创建可共享的statesetState 的方法,它们可以在父/子/兄弟组件之间使用。

    使用 React 18.2,路由器 6:

    package.json

    {
      "name": "react",
      "version": "1.0.0",
      "description": "React example starter project",
      "keywords": [
        "react",
        "starter"
      ],
      "main": "src/index.js",
      "dependencies": {
        "react": "18.2.0",
        "react-dom": "18.2.0",
        "react-router-dom": "^6.8.1",
        "react-scripts": "^5.0.1"
      },
      "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test --env=jsdom",
        "eject": "react-scripts eject"
      },
      "browserslist": [
        ">0.2%",
        "not dead",
        "not ie <= 11",
        "not op_mini all"
      ]
    }
    

    index.js

    import { StrictMode } from "react";
    import { createRoot } from "react-dom/client";
    
    import Provider from "./Provider";
    import App from "./App";
    
    const rootElement = document.getElementById("root");
    const root = createRoot(rootElement);
    
    root.render(
      <StrictMode>
        <Provider>
          <App />
        </Provider>
      </StrictMode>
    );
    

    Provider.js

    import React, { useState } from "react";
    
    export const defaultState = {
      App: "",
      SubComponentA: 0,
      SubComponentB: [],
    };
    
    export const defaultContextValue = {
      state: defaultState,
      setState: () => {},
    };
    
    export const AppContext = React.createContext(defaultContextValue);
    
    export default function App({ children }) {
      const [state, setState] = useState(defaultState);
    
      return (
        <AppContext.Provider value={{ state, setState }}>
          {children}
        </AppContext.Provider>
      );
    }
    

    App.js

    import React, { useContext, useEffect } from "react";
    import { AppContext, defaultState } from "./Provider";
    import ShowKeys from "./ShowKeys";
    import SubComponentA from "./SubComponentA";
    import SubComponentB from "./SubComponentB";
    
    export default function App() {
      const { state, setState } = useContext(AppContext);
    
      useEffect(() => {
        return () => setState(defaultState);
      }, []);
    
      // add text to the shared 'App' state value
      const onChangeInput = (e) => setState((s) => ({ ...s, App: e.target.value }));
    
      return (
        <div style={{ padding: "1rem" }}>
          <h1>Sibling / Child Component Context-Share</h1>
    
          <div
            style={{ border: "1px solid green", margin: "1rem", padding: "1rem" }}
          >
            <h3>App.js Context Values</h3>
            <ShowKeys />
            <input
              style={{ marginTop: "1rem" }}
              value={state.App}
              onChange={onChangeInput}
            />
          </div>
    
          <SubComponentA />
          <SubComponentB />
        </div>
      );
    }
    

    ShowKeys.js

    /**
     * Display context keys & values
     */
    import React, { useContext } from "react";
    import { AppContext } from "./Provider";
    
    export default function ShowKeys() {
      const { state } = useContext(AppContext);
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            justifyContent: "space-around",
          }}
        >
          {Object.keys(state).map((key) => {
            const value = state[key];
    
            return (
              <span>
                {key} = {key === "SubComponentB" ? JSON.stringify(value) : value}
              </span>
            );
          })}
        </div>
      );
    }
    

    SubComponentA.js

    import React, { useContext } from "react";
    import { AppContext } from "./Provider";
    import ShowKeys from "./ShowKeys";
    
    const SubComponentA = () => {
      const { state, setState } = useContext(AppContext);
    
      // increment the shared 'SubComponentA' state value
      const onModifyState = () =>
        setState((s) => ({ ...s, SubComponentA: s.SubComponentA + 420 }));
    
      return (
        <div style={{ border: "1px solid blue", margin: "1rem", padding: "1rem" }}>
          <h2>Sub Component A</h2>
          <ShowKeys />
          <button style={{ marginTop: "1rem" }} onClick={onModifyState}>
            Modify state
          </button>
        </div>
      );
    };
    
    export default SubComponentA;
    

    SubComponentB.js

    import React, { useContext } from "react";
    import { AppContext } from "./Provider";
    import ShowKeys from "./ShowKeys";
    
    const SubComponentB = () => {
      const { setState } = useContext(AppContext);
    
      // append a new random integer to the 'SubComponentB' state array value
      const onModifyState = () =>
        setState((s) => ({
          ...s,
          SubComponentB: [
            ...s.SubComponentB,
            {
              id: s.SubComponentB.length + 1,
            },
          ],
        }));
    
      return (
        <div style={{ border: "1px solid blue", margin: "1rem", padding: "1rem" }}>
          <h2>Sub Component B</h2>
          <ShowKeys />
          <button style={{ marginTop: "1rem" }} onClick={onModifyState}>
            Modify state
          </button>
        </div>
      );
    };
    
    export default SubComponentB;
    

    试用我刚刚创建的 working Sandbox 以更好地理解可共享状态。它有助于避免 prop-drilling 并且是在组件之间共享状态的干净解决方案。

    这是与所有 3 个组件交互后的最终结果——所有 3 个组件都知道彼此的状态。

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      • 2020-01-19
      • 2021-02-05
      • 1970-01-01
      相关资源
      最近更新 更多