![](/img/trans.png)
[英]How to pass data from Form to mapDispatchToProps in React
[英]React JS (Form Update Not Working) - How to set state immediately after getting data from API using mapDispatchToProps?
我对在这种情况下遇到的一些基础知识做出反应和工作非常新 - 我想在 API 调用之后立即设置 state。
设想:
2 Forms:
第一种形式 => 接受 id 并调用 api 以获取单个用户的数据
第二种形式 => 更新数据
问题:我想设置 state 在单击第一个表单上的提交按钮后获取数据时
import React, { Component, useEffect } from 'react'
import { connect } from 'react-redux';
import { getSingleUser } from '../redux/user/userActions';
export class UsersContainerUpdate extends Component {
constructor(props) {
super(props);
console.log(props.propFirstName);
this.state = {
id: '',
// first_name: props.propFirstName === '' ? '' : props.propFirstName,
first_name: props.propFirstName,
last_name: props.propLastName === '' ? '' : props.propLastName,
phone: props.propPhone === '' ? '' : props.propPhone,
email: props.propEmail === '' ? '' : props.propEmail,
address: props.propAddress === '' ? '' : props.propAddress,
city: props.propCity === '' ? '' : props.propCity,
state: props.propState === '' ? '' : props.propState,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
}
handleChange = (field, event) => {
this.setState({ [field]: event.target.value });
}
handleSubmit(event) {
// alert('A name was submitted: ' + this.state.name);
event.preventDefault();
const {
id
} = this.state;
const postData = {
id: id
};
// console.log(this.state);
// console.log(postData);
this.props.getSingleUserData(id);
// if (this.props.getSingleUserData(id)) {
// this.setState({
// ...this.state,
// first_name: this.props.propFirstName
// });
// }
}
handleUpdate(event) {
// alert('A name was submitted: ' + this.state.name);
event.preventDefault();
const {
first_name,
last_name,
phone,
email,
address,
city,
state
} = this.state;
const postData = {
first_name: first_name,
last_name: last_name,
phone: phone,
email: email,
address: address,
city: city,
state: state
};
console.log(this.state);
console.log("POSTDATA:", postData);
// alert('hi');
// this.props.updateUserData(id,postData);
}
render() {
return (
<div>
<h1>Update User By ID</h1>
<form onSubmit={this.handleSubmit}>
<div>
<label>ID:</label>
<input
type="text"
value={this.state.id}
onChange={(event, newValue) => this.handleChange('id', event)}
/>
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
<div>
<h1>Update User</h1>
<form onSubmit={this.handleUpdate}>
<div>
<label>First Name:</label>
<input
type="text"
value={this.state.first_name || this.props.propFirstName}
onChange={(event, newValue) => this.handleChange('first_name', event)}
/>
</div>
<div>
<label>Last Name:</label>
<input
type="text"
value={this.state.last_name || this.props.propLastName}
onChange={(event, newValue) => this.handleChange('last_name', event)} />
</div>
<div>
<label>Phone:</label>
<input
type="text"
value={this.state.phone || this.props.propPhone}
onChange={(event, newValue) => this.handleChange('phone', event)} />
</div>
<div>
<label>Email:</label>
<input
type="text"
value={this.state.email || this.props.propEmail}
onChange={(event, newValue) => this.handleChange('email', event)} />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
<div>
Notice Message : {this.props.propFirstName}
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
console.log(state.user);
return {
propFirstName: state.user.first_name,
propLastName: state.user.last_name,
propPhone: state.user.phone,
propEmail: state.user.email,
propAddress: state.user.address,
propCity: state.user.city,
propState: state.user.state
}
}
const mapDispatchToProps = dispatch => {
return {
getSingleUserData: id => dispatch(getSingleUser(id)),
// updateUserData: (id,postData) => dispatch(updateUser(id,postData))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(UsersContainerUpdate)
控制台输出是
第 81 行的控制台 output 是当前为空的 state。 我想把它放在那里。
提前致谢。 干杯!!
如果您的要求只是在 this.props.getSingleUserData(id) 中调用 API 后对 state,
方法 1:(不干净)向 getSingleUserData(id, setState) 添加一个参数并将 this.setState 作为参数传递,在 getSingleUserData 中,您可以使用 state 参考传递
方法 2:您可以从 getSingleUserData 返回promise并在解决后执行 setState
建议:将您的大组件分成单独的组件(例如一个用于获取用户 ID,一个用于用户数据更新)。 我们越多地将项目识别和拆分成有意义的单个组件,我们就会得到更多干净的代码。 此外,当您选择转向功能组件时,您可以减少大量带有挂钩的样板。
state.user
用于设置组件的 state 的初始值。 创建组件后,对这些道具的更改不会更改您的 state。 它们确实会更改您输入中的值,因为初始值是一个空字符串''
所以您默认显示来自props
的值。 这是非常具有误导性的,因为这些输入不反映当前的 state。
我敢打赌我可以删除至少一半的代码,但这不是重点。 但是花点时间想想为什么props.propState === ''? '': props.propState
props.propState === ''? '': props.propState
总是与props.propState
。
对于如何重写它,我有两个关键建议:
创建一个选择器 function selectUserById,它通过id
从您的 Redux selectUserById
中选择一个user
。 我认为将当前用户属性存储为state.user
的顶级属性是没有意义的,就像你现在拥有它们一样。 似乎您还有一个属性state.user.users
,它是所有已加载用户的array
,所以我会使用它。
const selectUserById = (state, id) => state.user.users.find(user => user.id === id);
或者更好的是,存储由 id 键入的用户的 object。
const selectUserById = (state, id) => state.user.users[id];
使用这种方法,我们要么拥有完整的用户 object,要么拥有undefined
。 在我们有真实数据之前,很容易检查undefined
并且根本不显示“更新用户”表单。 这比使用空字符串作为默认值更有意义。
我们可以从 Redux 访问完整的用户 object。 我不会在 state 中复制 object。 相反,我只会将 state 用于您更改的属性。 您将从 state 作为空 object 开始,并在修改其输入时为其添加属性。 您始终可以使用 object 传播将两者结合在一起。
const merged = {...existing, ...changes}
您能否使用 class 组件实施这些建议并connect
? 是的。 但是为什么要增加额外的障碍呢? 您的代码中的某些内容,例如this.handleChange.bind(this)
是过去的遗物,当时我们不得不这样做,因为没有更好的方法。 但是现在我们有更好的方法,所以你应该使用它们。
import "./App.css";
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "../store";
import { getSingleUser, updateUser } from "../store/slice";
const selectUserById = (state, id) => state.user.users[id];
const UserIdForm = ({ submitId }) => {
const [id, setId] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
submitId(id);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>ID:</label>
<input
type="text"
value={id}
onChange={(event) => setId(event.target.value)}
/>
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
);
};
const UpdateUserForm = ({ id }) => {
const [changes, setChanges] = useState > {};
const existing = useSelector((state) => selectUserById(state, id));
const dispatch = useDispatch();
// respond to changes in id by clearing the changes state and requesting the user
useEffect(() => {
dispatch(getSingleUser(id));
setChanges({});
}, [dispatch, setChanges, id]);
if (!existing) {
return <div>Loading User...</div>;
}
const merged = { ...existing, ...changes };
const handleChange = (property, event) => {
// in function components you have to copy the whole state
setChanges((prevChanges) => ({
...prevChanges,
[property]: event.target.value
}));
};
const handleUpdate = (event) => {
event.preventDefault();
const postData = { ...merged, id };
console.log("POSTDATA:", postData);
dispatch(updateUser(postData));
};
const renderInput = (property, label) => {
return (
<div>
<label>
{label}
<input
type="text"
value={merged[property]} // shows the current value or the updated value
onChange={(event) => handleChange(property, event)}
/>
</label>
</div>
);
};
return (
<form onSubmit={handleUpdate}>
{renderInput("first_name", "First Name:")}
{renderInput("last_name", "Last Name:")}
{renderInput("phone", "Phone:")}
{renderInput("email", "Email:")}
<div>
<input type="submit" value="Submit" />
</div>
</form>
);
};
const UsersContainerUpdate = () => {
// this is the id that was last submitted.
const [id, setId] = useState();
return (
<div>
<div>
<h1>Update User By ID</h1>
<UserIdForm submitId={setId} />
</div>
{!!id && ( // only load when there is an actual id
<div>
<h1>Update User</h1>
<UpdateUserForm id={id} />
</div>
)}
</div>
);
};
export default UsersContainerUpdate;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.