【问题标题】:How to pass prop from one component to another component如何将 prop 从一个组件传递到另一个组件
【发布时间】:2023-01-30 22:58:48
【问题描述】:

我正在尝试将名称、简历、经验、ctc 道具从 InputForUserProfile 传递到用户配置文件。这样我就可以在发生任何更改时将它们显示在我的用户配置文件中。但是当我将它们登录到控制台时,我无法传递它们并且它说未定义。注意(userprofile.js 是我创建的自定义 Web 组件)这些是我尝试过的代码。

应用程序.js:

import "./App.css";
import Routing from "./Routing";
function App() {
  return (
    <div className="App">
      <Routing/>
    </div>
  );
}
export default App;

路由.js:

import InputForUserProfile from "./InputForUserProfile";
import "./userprofile.js";
import { Link, Route, Routes } from "react-router-dom";
const Routing = ({name, bio, experience, ctc}) => {
    console.log("1", name);
  return (
    <>
      <nav>
        <ul>
          <li>
            <Link to="*">InputFields</Link>
          </li>
          <li>
            <Link to="/userprofile">userprofile</Link>
          </li>
        </ul>
      </nav>
      <Routes>
        <Route path="*" element={<InputForUserProfile />} />
        <Route
          path="/userprofile"
          element={
            <user-profile
              name={name}
              bio={bio}
              exp={experience}
              ctc={ctc}
            />
          }
        />
      </Routes>
    </>
  );
};
export default Routing;

InputForUserProfile.js:

import { useState } from "react";
import { Route, Routes } from "react-router-dom";
import "./userprofile.js";
const InputForUserProfile = () => {
  const [name, setName] = useState(localStorage.getItem("name") || "");
  const [bio, setBio] = useState(localStorage.getItem("bio") || "");
  const [experience, setExperience] = useState(
    localStorage.getItem("experience") || ""
  );
  const [ctc, setCtc] = useState(localStorage.getItem("ctc") || "");

  const handleSubmit = (event) => {
    event.preventDefault();
    localStorage.setItem("name", name);
    localStorage.setItem("bio", bio);
    localStorage.setItem("experience", experience);
    localStorage.setItem("ctc", ctc);
  };
  return (
    <>
      <form onSubmit={handleSubmit}>
        <label>
          Change User Name:
          <input
            type="text"
            placeholder="Change User Name"
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
        </label>
        <br />
        <label>
          Change User Bio:
          <textarea
            placeholder="Change User Bio"
            value={bio}
            onChange={(e) => setBio(e.target.value)}
          />
        </label>
        <br />
        <label>
          Change User Experience:
          <input
            type="text"
            placeholder="Change User Experience"
            value={experience}
            onChange={(e) => setExperience(e.target.value)}
          />
        </label>
        <br />
        <label>
          Change User CTC:
          <input
            type="text"
            placeholder="Change User CTC"
            value={ctc}
            onChange={(e) => setCtc(e.target.value)}
          />
        </label>
        <br />
        <button type="submit">Save Changes</button>
      </form>
      <Routes>
        <Route
          path="/userprofile"
          element={
            <user-profile name={name} bio={bio} exp={experience} ctc={ctc} />
          }
        />
      </Routes>
    </>
  );
};
export default InputForUserProfile;

userprofile.js(自定义网络组件):

class UserProfile extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
    this.shadowRoot.innerHTML = `
        <div id="profile">
        <br /><br />
        <img
          src=""
          alt="Profile Picture"
         
        />
        <h1>
          Name:
          <p id="name"></p>
        </h1>
    
        <h1>
          BIO:
          <p id="bio"></p>
        </h1>
        <h1>
          Experiance:
          <p id="exp"></p>
        </h1>
        <h1>
          CTC:
          <p id="CTC"></p>
        </h1>
        <input type="text" id="user-name"  class="hide-input" placeholder="changeusername">
        <input type="text" id="user-bio" class="hide-input" placeholder="changeuserbio">
        <input type="text" id="user-experience" class="hide-input" placeholder="changeuserexperience">
        <input type="text" id="user-CTC" class="hide-input" placeholder="changeuserCTC">
        <button id="save-button" class="hide-input" >save</button>
    
    
        <button id="edit-button"  >Edit Profile</button
        ><br /><br />
      </div>`;
  }

  connectedCallback() {
    const userVaule = this.shadowRoot.querySelector("div");
    this.shadowRoot.querySelector('#name').textContent = this.getAttribute("name");
    this.shadowRoot.querySelector('#bio').textContent = this.getAttribute("bio");
    this.shadowRoot.querySelector('#exp').textContent = this.getAttribute("exp");
    this.shadowRoot.querySelector('#CTC').textContent = this.getAttribute("ctc");
    userVaule
      .querySelector("#save-button")
      .addEventListener("click", this.saveProfile.bind(this));
    userVaule
      .querySelector("#edit-button")
      .addEventListener("click", this.editProfile.bind(this));
    userVaule.querySelectorAll("input, #save-button").forEach((el) => {
      el.classList.add("hide-input");
    });
    
  }
 editProfile() {
    this.shadowRoot.querySelectorAll("input, #save-button").forEach((el) => {
      el.classList.remove("hide-input");
    });

    this.shadowRoot.querySelector("#user-name").value =
      localStorage.getItem("name") || "";

    this.shadowRoot.querySelector("#user-bio").value =
      localStorage.getItem("bio") || "";

    this.shadowRoot.querySelector("#user-experience").value =
      localStorage.getItem("experience") || "";

    this.shadowRoot.querySelector("#user-CTC").value =
      localStorage.getItem("ctc") || "";

  }
  saveProfile() {
    this.shadowRoot.querySelectorAll("input, #save-button").forEach((el) => {
      el.classList.add("hide-input");
    });

    let name = this.shadowRoot.querySelector("#name");
    let bio = this.shadowRoot.querySelector("#bio");
    let exp = this.shadowRoot.querySelector("#exp");
    let CTC = this.shadowRoot.querySelector("#CTC");

    const userName = this.shadowRoot.querySelector("#user-name").value;
    localStorage.setItem("name", userName);

    const userBio = this.shadowRoot.querySelector("#user-bio").value;
    localStorage.setItem("bio", userBio);

    const userExperience =
      this.shadowRoot.querySelector("#user-experience").value;
    localStorage.setItem("exp", userExperience);

    const userCTC = this.shadowRoot.querySelector("#user-CTC").value;
    localStorage.setItem("CTC", userCTC);

    name.textContent = userName;
    bio.textContent = userBio;
    exp.textContent = userExperience;
    CTC.textContent = userCTC;

    
  }
}

customElements.define("user-profile", UserProfile);

【问题讨论】:

  • React 元素名称应以大写字母开头。
  • 实际上 <user-profile/> 不是一个 React 组件,它是一个由纯 Java 脚本组成的自定义 Web 组件 Web 组件的目的是在任何框架上工作,所以没问题
  • 您不能将其用作 routing.js 中的元素,因为它需要一个反应元素。
  • 兄弟代码工作正常我没有收到任何错误问题是在传递道具如果我错过理解请详细解释

标签: reactjs web-component


【解决方案1】:

您的代码有两个问题 - 一个是现在,另一个是将来。

首先是属性与属性. React 不支持将道具(非原始类型,如对象、数组等)传递给自定义元素。仅支持字符串、数字等值,它们作为属性而不是 DOM 属性传递。 (但这现在看起来不是问题,因为所有数据都只是字符串)。

绕过的方法是将您的 Web 组件包装在一些 React 组件中,并使用钩子 useRef 获取实际 Web 组件的实例,当道具更改时,您更改 Web 组件的道具,如:

function MyWrapperComp(props) {

  const ref = useRef(null);

  // Observe
  useEffect(() => {
    // Set the name as prop as opposed to attribute
    ref.current?.name = props.name;
  }, props.name);

  return (
    <user-profile ref={ref}></user-profile>
  );
}

如果您不介意只使用属性(而不是 props),那么第二个问题是 Web 组件的设计。可能会发生您的组件已初始化但 React 尚未将 props 传递给组件的情况(异步行为或类似行为 - 最初可能 localstorage 为空)。为了解决这个问题,您应该监听 attributeChangedCallback 生命周期事件或使用 MutationObserver 来观察 React 所做的属性更改。例如:

class UserProfile extends HTMLElement {

  // Rest of the code.

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'name' && oldValue !== newValue) {
      // Write code here when attribute `name` is changed.
    }
  }
}

最后回答你原来的问题 -如何将 prop 从一个组件传递到另一个组件- 除非您在 Web 组件之上使用任何声明抽象,否则唯一的方法是获取组件的实例并使用该实例将 props 传递给它。

附带一提,编写没有任何抽象的 Web 组件很麻烦,而且极易出错。我会推荐lit-element之类的东西来编写网络组件,它提供了许多实用程序来减轻痛苦。

【讨论】:

    猜你喜欢
    • 2020-12-30
    • 1970-01-01
    • 2021-10-31
    • 2019-11-06
    • 2018-11-10
    • 1970-01-01
    相关资源
    最近更新 更多