reactjs 是否可以通过将setState函数传递给链接组件来更改父组件的状态?

relj7zay  于 2023-02-12  发布在  React
关注(0)|答案(1)|浏览(177)

我设置了一个简单的链接,用于链接到列表中特定项的详细信息部分,但是,当我在Link组件中传递setter函数时,它会出错,因为所有其他状态变量都为空。
代码如下所示:

<Link
to={"device" + "/" + comp.hostname}
state={{
time:time,
date:date,
currentJobs: currentJobs,
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函数,代码也能正常工作,是不是Link组件不允许传递函数?

pgky5nke

pgky5nke1#

将setter放在另一个状态中是有问题的,考虑一下这种方法,它只是使用React上下文来创建可在父/子/兄弟组件之间使用的可共享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个组件都知道彼此的状态。

相关问题