我需要将哪些状态数据传递给 mapStateToProps
What state data do I need to pass to mapStateToProps
我第一次尝试使用 Redux 在我的应用程序中放入一个表单组件,我正在努力了解我必须为其创建 Reducers/Actions 的内容。
在其他组件中,我将我的用户和消息传递到 mapStateToProps 并且它们可以正常工作。然而,在这个组件中,我正在从我的后端为 componentDidMount 方法中的 table 字段提取数据,我不确定是否只有要更改的数据存储在 Redux 中。
我是否也需要为表单创建一个缩减器?还是直接发布到后端/节点/postgresql。我打算有一个 table 来更新所有最新数据,这样我就可以看到它被自动添加到检索到的数据的逻辑。
我是 React 的新手/JavaScript 所以我的逻辑可能有点不对,所以任何建议都将不胜感激。
diveLogForm.component.js
export class DiveLogForm extends Component {
constructor(props){
super(props);
this.handleSubmitDive = this.handleSubmitDive.bind(this);
this.onChangeDiveType = this.onChangeDiveType.bind(this);
this.onChangeSchoolName = this.onChangeSchoolName.bind(this);
this.onChangeCurrent = this.onChangeCurrent.bind(this);
this.onChangeVisibility = this.onChangeVisibility.bind(this);
this.onChangeDiveDate = this.onChangeDiveDate.bind(this);
this.onChangeMaxDepth = this.onChangeMaxDepth.bind(this);
this.onChangeDiverUserNumber = this.onChangeDiverUserNumber.bind(this);
this.onChangeVerifiedBySchool = this.onChangeVerifiedBySchool.bind(this);
this.onChangeDiveNotes = this.onChangeDiveNotes.bind(this);
this.onChangeDivePoint = this.onChangeDivePoint.bind(this);
this.state = {
diveTypeID: "",
diveSchoolNameID: "",
diveCurrentID: "",
diveVisibilityID: "",
diveDate: "",
diveMaxDepth: "",
diverUserNumber: "",
diveVerifiedBySchool: "",
diveNotes: "",
divePoint: "",
currentList: [],
regionList: [],
diveTypeList: [],
visibilityList: [],
diveSpotList: [],
currentUser: [],
loading: false,
};
}
componentDidMount() {
pullCurrentFields().then((response) => {
const { data } = response;
this.setState({ currentList: data.data });
});
pullRegionFields().then((response) => {
const { data } = response;
this.setState({ regionList: data.data });
});
pullDiveTypeFields().then((response) => {
const { data } = response;
this.setState({ diveTypeList: data.data });
});
pullVisibilityFields().then((response) => {
const { data } = response;
this.setState({ visibilityList: data.data });
});
pullDiveSpotFields().then((response) => {
const { data } = response;
this.setState({ diveSpotList: data.data });
});
//this.props.userDiveLogList();
}
onChangeDiveType(e) {
this.setState({
diveTypeID: e.target.value,
});
}
onChangeSchoolName(e) {
this.setState({
diveSchoolNameID: e.target.value,
});
}
onChangeCurrent(e) {
this.setState({
diveCurrentID: e.target.value,
});
}
onChangeVisibility(e){
this.setState({
diveVisibilityID: e.target.value,
});
}
onChangeDiveDate(e) {
this.setState({
diveDate: e.target.value,
});
}
onChangeMaxDepth(e){
this.setState({
diveMaxDepth: e.target.value,
});
}
onChangeDiverUserNumber(e){
this.setState({
diverUserNumber: e.target.value,
});
}
onChangeVerifiedBySchool(e){
this.setState({
diveVerifiedBySchool: e.target.value,
});
}
onChangeDiveNotes(e) {
this.setState({
diveNotes: e.target.value,
});
}
onChangeDivePoint(e){
this.setState({
divePoint: e.target.value,
});
}
handleSubmitDive(e) {
e.preventDefault();
this.setState({
loading: true,
});
this.form.validateAll();
//const {dispatch, history} = this.props;
if (this.checkBtn.context._errors.length === 0) {
this.props
.dispatch(registerUserDive(
this.state.diveTypeID,
this.state.diveSchoolNameID,
this.state.diveCurrentID,
this.state.diveVisibilityID,
this.state.diveDate,
this.state.diveMaxDepth,
this.state.diverUserNumber,
this.state.diveVerifiedBySchool,
this.state.diveNotes,
this.state.diveNotes))
.then(() => {
window.history.push("/divelogtable");
window.location.reload();
})
.catch(() => {
this.setState({
loading: false
});
});
}
}
render() {
const { classes } = this.props;
const { user: currentUser } = this.props;
if (this.state.currentList.length > 0) {
console.log("currentList", this.state.currentList);
}
if (this.state.regionList.length > 0) {
console.log("regionList", this.state.regionList);
}
if (this.state.diveTypeList.length > 0) {
console.log("diveTypeList", this.state.diveTypeList);
}
if (this.state.visibilityList.length > 0) {
console.log("visibilityList", this.state.visibilityList);
}
if (this.state.diveSpotList.length > 0) {
console.log("diveSpotList", this.state.diveSpotList);
}
return (
...materialUI form code
function mapStateToProps(state){
const { user } = state.auth;
const { regionList } = state.region;
const { currentList } = state.current;
const { diveTypeList } = state.diveType;
const { visibilityList } = state.visibility;
const { diveSpotList } = state.diveSpot;
return {
user,
regionList,
currentList,
diveTypeList,
visibilityList,
diveSpotList,
};
}
export default compose(
connect(
mapStateToProps,
),
withStyles(useStyles)
)(DiveLogForm);
因为我主要关心的是将我的表单数据添加到后端。我已经包含了 diveLog.service.js 文件 etc
export const registerDive = (diveTypeID, diveSchoolNameID, diveCurrentID, diveVisibilityID, diveDate, diveMaxDepth, diveEquipmentWorn, diverUserNumber, diveVerifiedBySchool, diveNotes, divePoint) => {
return axios.post(API_URL + "registerdive", {
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diveVerifiedBySchool,
diveNotes,
divePoint
});
};
diveLog.action.js
export const registerUserDive = (
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diverUserNumber,
diveVerifiedBySchool,
diveNotes,
divePoint) => (dispatch) => {
return registerDive(
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diveVerifiedBySchool,
diveNotes,
divePoint).then(
(response) => {
dispatch ({
type: successful_reg,
});
dispatch({
type: set_message,
payload: response.data.message,
});
return Promise.resolve();
},
(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: set_message,
payload: message,
});
return Promise.resolve();
},
(error) => {
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: failed_reg,
});
return Promise.reject();
}
);
};
我的 diveLog 注册操作可能有点偏离,因为我在编码时不理解 reducer 概念。
在我开始玩代码之前我不明白你的问题,但现在我明白你想做什么了。您有五个不同的列表(regionList
、currentList
等)。这些可能用于生成下拉菜单的选项。
现在您正在从您的 redux 商店中选择所有列表,并通过 mapStateToProps
将它们作为 props 提供。您永远不会使用列表将任何更改推送到 redux 存储。您正在 componentDidMount
中调用函数以从后端获取列表数据并将该数据存储在 this.state
中。这有点冲突,因为现在我们有两个地方的数据。我们是使用 this.props
中的列表,还是 this.state
中的列表?
最终由您决定要将哪些数据存储在何处。将数据存储在 redux 中的好处是它可以同时被多个不同的组件使用。它还允许您对后端进行一次调用,但为了获得这一优势,您需要编写带有条件检查的调用,以便仅在数据尚不存在时才进行调用。
Do I need to create a reducer for the form as well? or does it get posted straight to the backend / node / postgresql.
我建议将表单状态保留在组件本身中,因为部分填写的表单仅供此组件使用。
I intend to have a table that updates with all the most recent data so I can see the logic of it being automatically added to retrieved data.
我不确定什么是什么的父级,但是如果此表单显示在带有 table 的屏幕上,那么您可能希望将 isLoading
状态移至父级并通过传递给 props 的回调对其进行更新。这样 table 组件就知道它何时加载新行。或者,当你点击提交时,你可能会发送一个动作来将新的潜水存储到 redux(但我不会在每次击键时都存储它)。
In this component I am pulling data from my backend for table fields in the componentDidMount method and I am not sure if it is only data that is to be changed that get stored in Redux.
通用数据是 redux 的一个很好的候选者。所以在我看来,像所有地区的列表这样的东西存储在 redux 中是有意义的。
I am trying to get my head around what I have to create Reducers / Actions for.
当您有五个行为相似的不同列表时,最好定义将列表名称作为变量的通用操作和操作创建者。最好也有一个通用的 pullFields
函数!
这有点旁注,但建议任何刚起步的人都应该学习函数组件和钩子 useSelector
和 useDispatch
而不是 class 组件和connect
。编写组件变得容易多了,您正在做的一些事情 this.handleSubmitDive.bind(this)
可以很容易地避免。
我尝试在您的代码中 clean up the repetitions 但我没有解决 redux 问题。所以这里有一个使用 redux 处理数据获取的建议设置。其中一些有点“高级”,但我认为您应该能够复制并粘贴它。
定义一个 async thunk action,它从您的 API 中获取列表数据并将其存储在 redux 中,但如果数据已经加载,则不执行任何操作。
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
export const requireFieldData = createAsyncThunk(
'fields/requireData', // action name
// action expects to be called with the name of the field
async (field) => {
// you need to define a function to fetch the data by field name
const response = await pullField(field);
const { data } = response;
// what we return will be the action payload
return {
field,
items: data.data
};
},
// only fetch when needed: https://redux-toolkit.js.org/api/createAsyncThunk#canceling-before-execution
{
condition: (field, {getState}) => {
const {fields} = getState();
// check if there is already data by looking at the array length
if ( fields[field].length > 0 ) {
// return false to cancel execution
return false;
}
}
}
)
...
用于存储从 API 获取的数据的字段的缩减程序。 (使用 createSlice)
...
const fieldsSlice = createSlice({
name: 'fields',
initialState: {
current: [],
region: [],
diveType: [],
visibility: [],
diveSpot: [],
},
reducers: {},
extraReducers: {
// picks up the success action from the thunk
[requireFieldData.fulfilled.type]: (state, action) => {
// set the property based on the field property in the action
state[action.payload.field] = action.payload.items
}
}
})
export default fieldsSlice.reducer;
用户reducer需要能够添加潜水。您可能希望在此处存储更多信息并执行更多操作。
const userSlice = createSlice({
name: 'user',
initialState: {
dives: [],
},
reducers: {
// expects action creator to be called with a dive object
addDive: (state, action) => {
// append to the dives array
state.dives.push(action.payload)
}
}
})
export const { addDive } = userSlice.actions;
export default userSlice.reducer;
加入 fields
和 user
片的基本商店设置
import { configureStore } from "@reduxjs/toolkit";
import fieldsReducer from "./fields";
import userReducer from "./user";
export default configureStore({
// combine the reducers
reducer: {
user: userReducer,
fields: fieldsReducer,
}
});
组件可以使用 useSelector
而不是 mapStateToProps
从 redux 访问数据。我们将 dispatch
thunk 操作以确保加载所有列表。它们将以空数组开始,但会在操作完成后更新为新值。
const DiveLogForm = (props) => {
// select user object from redux
const user = useSelector(state => state.user);
// get the object with all the fields
const fields = useSelector(state => state.fields);
// can destructure individual fields
const { current, region, diveType, visibility, diveSpot } = fields;
// state for the current field value
const [dive, setDive] = useState({
typeID: "",
schoolNameID: "",
currentID: "",
visibilityID: "",
date: "",
maxDepth: "",
userNumber: "",
verifiedBySchool: "",
notes: "",
point: "",
});
// all onChange functions do the exact same thing, so you only need one
// pass to a component like onChange={handleChange('typeID')}
const handleChange = (property) => (e) => {
setDive({
// override the changed property and keep the rest
...dive,
[property]: e.target.value,
});
}
// get access to dispatch
const dispatch = useDispatch();
// useEffect with an empty dependency array is the same as componentDidMount
useEffect(() => {
// dispatch the action to load fields for each field type
// once loaded, the changes will be reflected in the fields variable from the useSelector
Object.keys(fields).forEach(name => dispatch(requireFieldData(name)));
}, []); // <-- empty array
const handleSubmitDive = (e) => {
// do some stuff with the form
// do we need to save this to the backend? or just to redux?
dispatch(addDive(dive));
}
return (
<form />
)
}
我第一次尝试使用 Redux 在我的应用程序中放入一个表单组件,我正在努力了解我必须为其创建 Reducers/Actions 的内容。
在其他组件中,我将我的用户和消息传递到 mapStateToProps 并且它们可以正常工作。然而,在这个组件中,我正在从我的后端为 componentDidMount 方法中的 table 字段提取数据,我不确定是否只有要更改的数据存储在 Redux 中。
我是否也需要为表单创建一个缩减器?还是直接发布到后端/节点/postgresql。我打算有一个 table 来更新所有最新数据,这样我就可以看到它被自动添加到检索到的数据的逻辑。
我是 React 的新手/JavaScript 所以我的逻辑可能有点不对,所以任何建议都将不胜感激。
diveLogForm.component.js
export class DiveLogForm extends Component {
constructor(props){
super(props);
this.handleSubmitDive = this.handleSubmitDive.bind(this);
this.onChangeDiveType = this.onChangeDiveType.bind(this);
this.onChangeSchoolName = this.onChangeSchoolName.bind(this);
this.onChangeCurrent = this.onChangeCurrent.bind(this);
this.onChangeVisibility = this.onChangeVisibility.bind(this);
this.onChangeDiveDate = this.onChangeDiveDate.bind(this);
this.onChangeMaxDepth = this.onChangeMaxDepth.bind(this);
this.onChangeDiverUserNumber = this.onChangeDiverUserNumber.bind(this);
this.onChangeVerifiedBySchool = this.onChangeVerifiedBySchool.bind(this);
this.onChangeDiveNotes = this.onChangeDiveNotes.bind(this);
this.onChangeDivePoint = this.onChangeDivePoint.bind(this);
this.state = {
diveTypeID: "",
diveSchoolNameID: "",
diveCurrentID: "",
diveVisibilityID: "",
diveDate: "",
diveMaxDepth: "",
diverUserNumber: "",
diveVerifiedBySchool: "",
diveNotes: "",
divePoint: "",
currentList: [],
regionList: [],
diveTypeList: [],
visibilityList: [],
diveSpotList: [],
currentUser: [],
loading: false,
};
}
componentDidMount() {
pullCurrentFields().then((response) => {
const { data } = response;
this.setState({ currentList: data.data });
});
pullRegionFields().then((response) => {
const { data } = response;
this.setState({ regionList: data.data });
});
pullDiveTypeFields().then((response) => {
const { data } = response;
this.setState({ diveTypeList: data.data });
});
pullVisibilityFields().then((response) => {
const { data } = response;
this.setState({ visibilityList: data.data });
});
pullDiveSpotFields().then((response) => {
const { data } = response;
this.setState({ diveSpotList: data.data });
});
//this.props.userDiveLogList();
}
onChangeDiveType(e) {
this.setState({
diveTypeID: e.target.value,
});
}
onChangeSchoolName(e) {
this.setState({
diveSchoolNameID: e.target.value,
});
}
onChangeCurrent(e) {
this.setState({
diveCurrentID: e.target.value,
});
}
onChangeVisibility(e){
this.setState({
diveVisibilityID: e.target.value,
});
}
onChangeDiveDate(e) {
this.setState({
diveDate: e.target.value,
});
}
onChangeMaxDepth(e){
this.setState({
diveMaxDepth: e.target.value,
});
}
onChangeDiverUserNumber(e){
this.setState({
diverUserNumber: e.target.value,
});
}
onChangeVerifiedBySchool(e){
this.setState({
diveVerifiedBySchool: e.target.value,
});
}
onChangeDiveNotes(e) {
this.setState({
diveNotes: e.target.value,
});
}
onChangeDivePoint(e){
this.setState({
divePoint: e.target.value,
});
}
handleSubmitDive(e) {
e.preventDefault();
this.setState({
loading: true,
});
this.form.validateAll();
//const {dispatch, history} = this.props;
if (this.checkBtn.context._errors.length === 0) {
this.props
.dispatch(registerUserDive(
this.state.diveTypeID,
this.state.diveSchoolNameID,
this.state.diveCurrentID,
this.state.diveVisibilityID,
this.state.diveDate,
this.state.diveMaxDepth,
this.state.diverUserNumber,
this.state.diveVerifiedBySchool,
this.state.diveNotes,
this.state.diveNotes))
.then(() => {
window.history.push("/divelogtable");
window.location.reload();
})
.catch(() => {
this.setState({
loading: false
});
});
}
}
render() {
const { classes } = this.props;
const { user: currentUser } = this.props;
if (this.state.currentList.length > 0) {
console.log("currentList", this.state.currentList);
}
if (this.state.regionList.length > 0) {
console.log("regionList", this.state.regionList);
}
if (this.state.diveTypeList.length > 0) {
console.log("diveTypeList", this.state.diveTypeList);
}
if (this.state.visibilityList.length > 0) {
console.log("visibilityList", this.state.visibilityList);
}
if (this.state.diveSpotList.length > 0) {
console.log("diveSpotList", this.state.diveSpotList);
}
return (
...materialUI form code
function mapStateToProps(state){
const { user } = state.auth;
const { regionList } = state.region;
const { currentList } = state.current;
const { diveTypeList } = state.diveType;
const { visibilityList } = state.visibility;
const { diveSpotList } = state.diveSpot;
return {
user,
regionList,
currentList,
diveTypeList,
visibilityList,
diveSpotList,
};
}
export default compose(
connect(
mapStateToProps,
),
withStyles(useStyles)
)(DiveLogForm);
因为我主要关心的是将我的表单数据添加到后端。我已经包含了 diveLog.service.js 文件 etc
export const registerDive = (diveTypeID, diveSchoolNameID, diveCurrentID, diveVisibilityID, diveDate, diveMaxDepth, diveEquipmentWorn, diverUserNumber, diveVerifiedBySchool, diveNotes, divePoint) => {
return axios.post(API_URL + "registerdive", {
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diveVerifiedBySchool,
diveNotes,
divePoint
});
};
diveLog.action.js
export const registerUserDive = (
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diverUserNumber,
diveVerifiedBySchool,
diveNotes,
divePoint) => (dispatch) => {
return registerDive(
diveTypeID,
diveSchoolNameID,
diveCurrentID,
diveVisibilityID,
diveDate,
diveMaxDepth,
diveVerifiedBySchool,
diveNotes,
divePoint).then(
(response) => {
dispatch ({
type: successful_reg,
});
dispatch({
type: set_message,
payload: response.data.message,
});
return Promise.resolve();
},
(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: set_message,
payload: message,
});
return Promise.resolve();
},
(error) => {
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: failed_reg,
});
return Promise.reject();
}
);
};
我的 diveLog 注册操作可能有点偏离,因为我在编码时不理解 reducer 概念。
在我开始玩代码之前我不明白你的问题,但现在我明白你想做什么了。您有五个不同的列表(regionList
、currentList
等)。这些可能用于生成下拉菜单的选项。
现在您正在从您的 redux 商店中选择所有列表,并通过 mapStateToProps
将它们作为 props 提供。您永远不会使用列表将任何更改推送到 redux 存储。您正在 componentDidMount
中调用函数以从后端获取列表数据并将该数据存储在 this.state
中。这有点冲突,因为现在我们有两个地方的数据。我们是使用 this.props
中的列表,还是 this.state
中的列表?
最终由您决定要将哪些数据存储在何处。将数据存储在 redux 中的好处是它可以同时被多个不同的组件使用。它还允许您对后端进行一次调用,但为了获得这一优势,您需要编写带有条件检查的调用,以便仅在数据尚不存在时才进行调用。
Do I need to create a reducer for the form as well? or does it get posted straight to the backend / node / postgresql.
我建议将表单状态保留在组件本身中,因为部分填写的表单仅供此组件使用。
I intend to have a table that updates with all the most recent data so I can see the logic of it being automatically added to retrieved data.
我不确定什么是什么的父级,但是如果此表单显示在带有 table 的屏幕上,那么您可能希望将 isLoading
状态移至父级并通过传递给 props 的回调对其进行更新。这样 table 组件就知道它何时加载新行。或者,当你点击提交时,你可能会发送一个动作来将新的潜水存储到 redux(但我不会在每次击键时都存储它)。
In this component I am pulling data from my backend for table fields in the componentDidMount method and I am not sure if it is only data that is to be changed that get stored in Redux.
通用数据是 redux 的一个很好的候选者。所以在我看来,像所有地区的列表这样的东西存储在 redux 中是有意义的。
I am trying to get my head around what I have to create Reducers / Actions for.
当您有五个行为相似的不同列表时,最好定义将列表名称作为变量的通用操作和操作创建者。最好也有一个通用的 pullFields
函数!
这有点旁注,但建议任何刚起步的人都应该学习函数组件和钩子 useSelector
和 useDispatch
而不是 class 组件和connect
。编写组件变得容易多了,您正在做的一些事情 this.handleSubmitDive.bind(this)
可以很容易地避免。
我尝试在您的代码中 clean up the repetitions 但我没有解决 redux 问题。所以这里有一个使用 redux 处理数据获取的建议设置。其中一些有点“高级”,但我认为您应该能够复制并粘贴它。
定义一个 async thunk action,它从您的 API 中获取列表数据并将其存储在 redux 中,但如果数据已经加载,则不执行任何操作。
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
export const requireFieldData = createAsyncThunk(
'fields/requireData', // action name
// action expects to be called with the name of the field
async (field) => {
// you need to define a function to fetch the data by field name
const response = await pullField(field);
const { data } = response;
// what we return will be the action payload
return {
field,
items: data.data
};
},
// only fetch when needed: https://redux-toolkit.js.org/api/createAsyncThunk#canceling-before-execution
{
condition: (field, {getState}) => {
const {fields} = getState();
// check if there is already data by looking at the array length
if ( fields[field].length > 0 ) {
// return false to cancel execution
return false;
}
}
}
)
...
用于存储从 API 获取的数据的字段的缩减程序。 (使用 createSlice)
...
const fieldsSlice = createSlice({
name: 'fields',
initialState: {
current: [],
region: [],
diveType: [],
visibility: [],
diveSpot: [],
},
reducers: {},
extraReducers: {
// picks up the success action from the thunk
[requireFieldData.fulfilled.type]: (state, action) => {
// set the property based on the field property in the action
state[action.payload.field] = action.payload.items
}
}
})
export default fieldsSlice.reducer;
用户reducer需要能够添加潜水。您可能希望在此处存储更多信息并执行更多操作。
const userSlice = createSlice({
name: 'user',
initialState: {
dives: [],
},
reducers: {
// expects action creator to be called with a dive object
addDive: (state, action) => {
// append to the dives array
state.dives.push(action.payload)
}
}
})
export const { addDive } = userSlice.actions;
export default userSlice.reducer;
加入 fields
和 user
片的基本商店设置
import { configureStore } from "@reduxjs/toolkit";
import fieldsReducer from "./fields";
import userReducer from "./user";
export default configureStore({
// combine the reducers
reducer: {
user: userReducer,
fields: fieldsReducer,
}
});
组件可以使用 useSelector
而不是 mapStateToProps
从 redux 访问数据。我们将 dispatch
thunk 操作以确保加载所有列表。它们将以空数组开始,但会在操作完成后更新为新值。
const DiveLogForm = (props) => {
// select user object from redux
const user = useSelector(state => state.user);
// get the object with all the fields
const fields = useSelector(state => state.fields);
// can destructure individual fields
const { current, region, diveType, visibility, diveSpot } = fields;
// state for the current field value
const [dive, setDive] = useState({
typeID: "",
schoolNameID: "",
currentID: "",
visibilityID: "",
date: "",
maxDepth: "",
userNumber: "",
verifiedBySchool: "",
notes: "",
point: "",
});
// all onChange functions do the exact same thing, so you only need one
// pass to a component like onChange={handleChange('typeID')}
const handleChange = (property) => (e) => {
setDive({
// override the changed property and keep the rest
...dive,
[property]: e.target.value,
});
}
// get access to dispatch
const dispatch = useDispatch();
// useEffect with an empty dependency array is the same as componentDidMount
useEffect(() => {
// dispatch the action to load fields for each field type
// once loaded, the changes will be reflected in the fields variable from the useSelector
Object.keys(fields).forEach(name => dispatch(requireFieldData(name)));
}, []); // <-- empty array
const handleSubmitDive = (e) => {
// do some stuff with the form
// do we need to save this to the backend? or just to redux?
dispatch(addDive(dive));
}
return (
<form />
)
}