为什么我的子组件在React中更改状态时不更新数据?

huangapple go评论78阅读模式
英文:

Why isn't my child component updating data when changing the state in React?

问题

以下是您提供的代码的中文翻译:

主页面:

const index = (props) => {
  const [selectedUser, setSelectedUser] = useState(null);
  const [state, setState] = useState("Index");

  const onChange = (item) => {
    setState("Edit");
    setSelectedUser(item);
  };

  const onClick = (e, item) => {
    if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
      onChange(item);
    } else {
      console.log('在按键时阻止了 "onClick" 事件');
    }
  };

  const renderComponent = () => {
    switch (state) {
      case "Index":
        return (
          <>
            <div className="btn" onClick={(e) => setState("Edit")}>
              + 新员工
            </div>
            <img src="/storage/illustrations/collaboration.svg" />
          </>
        );
      case "Edit":
        return (
          <div>
            <StaffForm profile={selectedUser} />
          </div>
        );
    }
  };

  return (
    <>
      <div>
        <div>
          <h1>员工</h1>
        </div>

        <div>
          <div>
            {profiles.map((item, index) => {
              return (
                <div key={index} onClick={(e) => onClick(e, item)}>
                  <input
                    type={"radio"}
                    name={"staff"}
                    checked={state === item}
                    onChange={(e) => onChange(item)}
                  />

                  <span>{item.user.name}</span>
                </div>
              );
            })}
          </div>
          <div>{renderComponent()}</div>
        </div>
      </div>
    </>
  );
};

员工表单组件:

const StaffForm = ({ profile }) => {
  const { data, setData, post, processing, errors, reset } = useForm({
    email: profile ? profile.user.email : "",
    name: profile ? profile.user.name : "",
    phone_number: profile ? profile.user.phone_number : "",
    avatar: profile ? profile.user.avatar : "",
  });
  const [file, setFile] = useState(data.avatar);
  const handleImageUpload = (e) => {
    setFile(URL.createObjectURL(e.target.files[0]));
    setData("avatar", e.target.files[0]);
  };
  const onHandleChange = (event) => {
    setData(
      event.target.name,
      event.target.type === "checkbox"
        ? event.target.checked
        : event.target.value
    );
  };

  return (
    <div>
      <ImageUpload
        name={data.name}
        file={file}
        handleImageUpload={handleImageUpload}
      />
      <TextInput
        type="text"
        name="name"
        value={data.name}
        autoComplete="name"
        isFocused={true}
        onChange={onHandleChange}
        placeholder={"姓名"}
        required
      />
      <TextInput
        type="text"
        name="phone_number"
        value={data.phone_number}
        autoComplete="phone_number"
        placeholder={"电话号码"}
        onChange={onHandleChange}
        required
      />
      <TextInput
        type="email"
        name="email"
        value={data.email}
        autoComplete="email"
        onChange={onHandleChange}
        placeholder={"电子邮件"}
        required
      />
    </div>
  );
};

请注意,我已经将代码中的 HTML 标记翻译为了合适的中文描述,但代码本身保持不变。如果您有任何进一步的问题或需要额外的帮助,请随时提出。

英文:

I have a list of users and I want to display in another component on the same page the user data in input fields for every user that I click on.

When no user is selected, I want the component to just render some text and a button to add a user. When the button is clicked the component renders the form with empty input fields so that we can add a new user.

I tried the following, but it's just showing the data for the first one I click on. It's not updating.

The main page:

const index = (props) =&gt; {
const [selectedUser, setSelectedUser] = useState(null);
const [state, setState] = useState(&quot;Index&quot;);
const onChange = (item) =&gt; {
setState(&quot;Edit&quot;);
setSelectedUser(item);
};
const onClick = (e, item) =&gt; {
if (e.type === &quot;click&quot; &amp;&amp; e.clientX !== 0 &amp;&amp; e.clientY !== 0) {
onChange(item);
} else {
console.log(&#39;prevented &quot;onClick&quot; on keypress&#39;);
}
};
const renderComponent = () =&gt; {
switch (state) {
case &quot;Index&quot;:
return (
&lt;&gt;
&lt;div className=&quot;btn&quot; onClick={(e) =&gt; setState(&quot;Edit&quot;)}&gt;
+ New Staff
&lt;/div&gt;
&lt;img src=&quot;/storage/illustrations/collaboration.svg&quot; /&gt;
&lt;/&gt;
);
case &quot;Edit&quot;:
return (
&lt;div&gt;
&lt;StaffForm profile={selectedUser} /&gt;
&lt;/div&gt;
);
}
};
return (
&lt;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1&gt;Staff&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
{profiles.map((item, index) =&gt; {
return (
&lt;div key={index} onClick={(e) =&gt; onClick(e, item)}&gt;
&lt;input
type={&quot;radio&quot;}
name={&quot;staff&quot;}
checked={state === item}
onChange={(e) =&gt; onChange(item)}
/&gt;
&lt;span&gt;{item.user.name}&lt;/span&gt;
&lt;/div&gt;
);
})}
&lt;/div&gt;
&lt;div&gt;{renderComponent()}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/&gt;
);
};

The Staff Form Component:

const StaffForm = ({ profile }) =&gt; {
const { data, setData, post, processing, errors, reset } = useForm({
email: profile ? profile.user.email : &quot;&quot;,
name: profile ? profile.user.name : &quot;&quot;,
phone_number: profile ? profile.user.phone_number : &quot;&quot;,
avatar: profile ? profile.user.avatar : &quot;&quot;,
});
const [file, setFile] = useState(data.avatar);
const handleImageUpload = (e) =&gt; {
setFile(URL.createObjectURL(e.target.files[0]));
setData(&quot;avatar&quot;, e.target.files[0]);
};
const onHandleChange = (event) =&gt; {
setData(
event.target.name,
event.target.type === &quot;checkbox&quot;
? event.target.checked
: event.target.value
);
};
return (
&lt;div&gt;
&lt;ImageUpload
name={data.name}
file={file}
handleImageUpload={handleImageUpload}
/&gt;
&lt;TextInput
type=&quot;text&quot;
name=&quot;name&quot;
value={data.name}
autoComplete=&quot;name&quot;
isFocused={true}
onChange={onHandleChange}
placeholder={t(&quot;Name&quot;)}
required
/&gt;
&lt;TextInput
type=&quot;text&quot;
name=&quot;phone_number&quot;
value={data.phone_number}
autoComplete=&quot;phone_number&quot;
placeholder={t(&quot;Phone Number&quot;)}
onChange={onHandleChange}
required
/&gt;
&lt;TextInput
type=&quot;email&quot;
name=&quot;email&quot;
value={data.email}
autoComplete=&quot;email&quot;
onChange={onHandleChange}
placeholder={t(&quot;Email&quot;)}
required
/&gt;
&lt;/div&gt;
);
};

答案1

得分: 1

  1. 首先,有一件事情你应该避免,那就是 renderComponent() 的调用。查看这里 视频中提到的第一个错误。这很可能会解决你的问题,但即使不解决,视频也会解释为什么不应该使用它。

  2. 还有一件引起我注意的事情(可能与你的问题无关,但值得知道),那就是 onChange 函数。当两个状态同时改变时,可能会引发问题,查看这篇关于何时使用 useReducer 钩子的文章

  3. 还要小心命名 React 组件,它们需要使用大写字母开头,这个问题包含了合适的答案来解释这一点

(要解决你的问题,只需遵循列表中的第一项。对于代码质量和美观性,我在整体上也有一些改进建议,如果需要更多详细信息,请私信我。)

英文:
  1. First of all something you should avoid is the renderComponent() call.Check here the first mistake mentioned in this video. This will most likely fix your problem but even if it doesn't the video explains why it should not be used.
  2. Something else that caught my eye(possibly unrelated to your question but good to know) is the onChange function. When two pieces of state change together it is a potential source of problems, check out this article on when to use the useReducer hook.
  3. Also be careful with naming React Components, they need to be capital case, this question contains appropriate answers explaining it.
    (To only solve your problem stick to no.1 of this list, there are some improvements i'd do here overall for code quality and beauty, msg me for more details)

huangapple
  • 本文由 发表于 2023年1月9日 05:33:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75051470.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定