我正试图通过创建多步表单(reactjs(来学习redux,一切都很好,除了当我点击一个按钮时,所有数据都应该转到一个变量finalData
,但它不起作用,我得到了:
TypeError: finalData.map is not a function
当我检查console.log(userData);
时,我得到了所有的数据,但我希望数据进入finalData
,而changeFinalData
是更新它的。
当我控制台日志finalData时,我得到:finalData => [...finalData, userData]
。
我做错了什么?
我的代码:
import React, { useContext } from "react";
import { Form, Input, Button } from "antd";
import "antd/dist/antd.css";
// import { multiStepContext } from "../StepContext";
//-------------
import { useDispatch, useSelector } from "react-redux";
import {
changeName,
changeUserId,
selectId,
selectName,
changeSetStep,
changeUserData,
changeFinalData,
selectCurrentStep,
selectUserData,
selectFinalData,
} from "../features/app/appSlice";
function ThirdStep() {
// const { setStep, userData, setUserData, submitData } =
// useContext(multiStepContext);
//----
const dispatch = useDispatch();
const userData = useSelector(selectUserData);
const finalDataa = useSelector(selectFinalData);
console.log(userData);
const submitData = () => {
dispatch(changeFinalData((finalDataa) => [...finalDataa, userData]));
changeUserData("");
changeSetStep(1);
};
return (
<Form>
<Form.Item
label="City"
name="City"
initialValue={userData["city"] || ""}
onChange={(e) =>
dispatch(changeUserData({ ...userData, city: e.target.value }))
}
>
<Input type="string" />
</Form.Item>
<Form.Item
label="Landmark"
name="Landmark"
initialValue={userData["landmark"] || ""}
onChange={(e) =>
dispatch(changeUserData({ ...userData, landmark: e.target.value }))
}
>
<Input type="string" />
</Form.Item>
<Form.Item
label="Postal Code"
name="Postal Code"
initialValue={userData["postcode"] || ""}
onChange={(e) =>
dispatch(changeUserData({ ...userData, postcode: e.target.value }))
}
>
<Input type="string" />
</Form.Item>
<div>
<Button
variant="contained"
onClick={() => dispatch(changeSetStep(2))}
color="secondary"
>
Back
</Button>
<span> </span>
<Button
variant="contained"
onClick={() => submitData()}
color="primary"
>
Submit
</Button>
</div>
</Form>
);
}
export default ThirdStep;
我的appSlice.js:
import { createSlice } from "@reduxjs/toolkit";
export const appSlice = createSlice({
name: "app",
initialState: {
userData: [],
finalData: [],
currentStep: 1,
},
reducers: {
changeSetStep: (state, action) => {
state.currentStep = action.payload;
},
changeUserData: (state, action) => {
state.userData = action.payload;
},
changeFinalData: (state, action) => {
state.finalData = action.payload;
},
},
});
export const {
changeSetStep,
changeUserData,
changeFinalData,
} = appSlice.actions;
export const selectCurrentStep = (state) => state.app.currentStep;
export const selectUserData = (state) => state.app.userData;
export const selectFinalData = (state) => state.app.finalData;
export default appSlice.reducer;
DisplayData.js:
import React, { useContext } from "react";
import {
TableContainer,
TableHead,
TableBody,
TableCell,
TableRow,
Table,
} from "@material-ui/core";
import { useSelector } from "react-redux";
import { selectFinalData } from "../features/app/appSlice";
// import { multiStepContext } from "../StepContext";
function DisplayData() {
// const { finalData } = useContext(multiStepContext);
const finalDataa = useSelector(selectFinalData);
console.log(finalDataa);
return (
<div>
<TableContainer style={{ display: "flex", justifyContent: "center" }}>
<Table
border="1"
style={{ width: "70%", justifyContent: "center" }}
size="small"
aria-label="caption table"
>
<TableHead>
<TableRow
style={{ backgroundColor: "burlywood", color: "aliceblue" }}
>
<TableCell>First Name </TableCell>
<TableCell>Last Name </TableCell>
<TableCell>Contact Number </TableCell>
<TableCell>Email Address </TableCell>
<TableCell>Country </TableCell>
<TableCell>District </TableCell>
<TableCell>City </TableCell>
<TableCell>Landmark </TableCell>
<TableCell>Postal Code </TableCell>
</TableRow>
</TableHead>
<TableBody>
{finalDataa.map((data) => (
<TableRow key={data.email}>
<TableCell>{data.firstName} </TableCell>
<TableCell>{data.lastName} </TableCell>
<TableCell>{data.contact} </TableCell>
<TableCell>{data.email} </TableCell>
<TableCell>{data.country} </TableCell>
<TableCell>{data.district} </TableCell>
<TableCell>{data.city} </TableCell>
<TableCell>{data.landmark} </TableCell>
<TableCell>{data.postcode} </TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
);
}
export default DisplayData;
我的应用程序js:
import { useState } from "react";
import "./App.css";
import Header from "./components/Header";
import FirstStep from "./components/FirstStep";
import SecondStep from "./components/SecondStep";
import ThirdStep from "./components/ThirdStep";
import { Stepper, StepLabel, Step } from "@material-ui/core";
// import { multiStepContext } from "./StepContext";
import { useContext } from "react";
import DisplayData from "./components/DisplayData";
//---
import { useDispatch, useSelector } from "react-redux";
import {
changeName,
changeUserId,
selectId,
selectName,
changeSetStep,
changeUserData,
changeFinalData,
selectCurrentStep,
selectUserData,
selectFinalData,
} from "./features/app/appSlice";
//--
function App() {
const SelectFinalData = useSelector(selectFinalData);
const SelectCurrentStep = useSelector(selectCurrentStep);
// const [name,setName]=useState('kalle')
// const { currentStep, finalData } = useContext(multiStepContext);
const showStep = (step) => {
switch (step) {
case 1:
return <FirstStep />;
case 2:
return <SecondStep />;
case 3:
return <ThirdStep />;
}
};
return (
<div className="App">
<header className="App-header">
<h3 style={{ color: "red", textDecoration: "underline" }}>
Reactjs multi step Application
</h3>
<div className="center-stepper">
<Stepper
style={{ width: "18%" }}
activeStep={SelectCurrentStep - 1}
orientation="horizontal"
>
<Step>
<StepLabel></StepLabel>
</Step>
<Step>
<StepLabel></StepLabel>
</Step>
<Step>
<StepLabel></StepLabel>
</Step>
</Stepper>
</div>
{showStep(SelectCurrentStep)}
{SelectFinalData.length > 0 ? <DisplayData /> : ""}
</header>{" "}
</div>
);
}
export default App;
问题
这里的问题是,您正试图在UI代码中实现reducer逻辑。您将函数存储在状态中,而不是实际更新状态值。
dispatch(changeFinalData((finalDataa) => [...finalDataa, userData]));
这只是将函数(finalDataa) => [...finalDataa, userData]
存储到state.app.finalData
状态中的状态中。
解决方案
而可以只调用reducer中的action payload函数并将当前finalData
状态传递给它
changeFinalData: (state, action) => {
state.finalData = action.payload(state.finalData);
},
这不是你想要保持状态的方式。相反,您将希望在操作负载中传递要更新状态的数据。
changeFinalData: (state, action) => {
state.finalData.push(action.payload);
},
并使用数据有效载荷调度操作。
dispatch(changeFinalData(userData));
由于您在所有其他reducer案例中都使用了类似的逻辑,因此您将希望实现类似的更新。这样,reducer函数就可以保持对状态更新方式的控制。