I am fetching the data to populate it on the form but when I try to edit the data in the input, the input value will return to its original value and it is because of the get method that is infinitely render on the component. I really need your eyes to see something that have missed or missed up. Thanks in advance y'all.
fetch method
import * as api from '../api/profile';
export const getProfile = () => async (dispatch) => {
try {
const { data } = await api.fetchProfile();
dispatch({ type: 'FETCH_ALL', payload: data });
} catch (error) {
console.log(error.message);
}
}
Profile container
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getProfile } from '../../../actions/profile'; //fetch method
import Profile from './Profile';
function Index() {
const dispatch = useDispatch();
const posts = useSelector((state) => state.posts);
const currentId = useState(null);
useEffect(() => {
dispatch(getProfile());
}, [currentId, dispatch]);
return (
<div className="custom-container">
{posts.map((profile) => (
<div key={profile._id}>
<Profile profile={profile} currentId={currentId} />
</div>
))}
</div>
);
}
export default Index;
Profile form component
import './Profile.css';
import { React, useState, useEffect } from 'react';
import Button from 'react-bootstrap/Button';
import { TextField } from '#material-ui/core';
import { useDispatch, useSelector } from 'react-redux';
import { updateProfile } from '../../../actions/profile';
const Profile = ({ profile, currentId }) => {
const dispatch = useDispatch();
currentId = profile._id;
const [postData, setPostData] = useState(
{
profile: {
name: "",
description: "",
email: "",
number: "",
}
}
);
const post = useSelector((state) => currentId ? state.posts.find((p) => p._id === currentId) : null);
useEffect(() => {
if(post) setPostData(post);
}, [post])
const handleSubmit = (e) => {
e.preventDefault();
if(currentId) {
dispatch(updateProfile(currentId, postData));
}
}
return (
<form autoComplete="off" noValidate className="form" onSubmit={handleSubmit}>
<TextField
id="name"
name="name"
className="name"
label="Full Name"
variant="outlined"
value={postData.profile.name}
onChange={(e) => setPostData({...postData, profile: {...postData.profile, name: e.target.value}})}
/>
<TextField
id="outlined-multiline-static"
label="Multiline"
multiline
rows={4}
variant="outlined"
size="small"
className="mb-3"
name="description"
value={postData.profile.description}
onChange={(e) => setPostData({...postData, profile: {...postData.profile, description: e.target.value}})}
fullWidth
/>
<TextField
id="email"
label="Email"
variant="outlined"
size="small"
className="mb-3"
name="email"
value={postData.profile.email}
onChange={(e) => setPostData({...postData, profile: {...postData.profile, email: e.target.value}})}
/>
<TextField
id="phone"
label="Phone Number"
variant="outlined"
size="small"
name="phone"
value={postData.profile.number}
onChange={(e) => setPostData({...postData, profile: {...postData.profile, number: e.target.value}})}
/>
<Button variant="light" type="submit" className="Save">Save</Button>
</form>
);
}
export default Profile;
In useEffect you have passed like this , in Profile Container
useEffect(() => {
dispatch(getProfile());
}, [currentId, dispatch]);
in params you have passed dispatch also , so it will call dispatch every time dispatch runs , so it is called infinite times , remove it
It might be because of useEffect.
useEffect(() => {
if(post) setPostData(post);
}, [post])
The post will be a different object each time. check for post property in useEffect dependency like:
useEffect(() => {
if(post) setPostData(post);
}, [post.profile.description])
Also, why are you changing prop value below in Profile component?
currentId = profile._id
Related
I have 2 components home and tiny tiny is imported inside home as u can see in the code
I am trying to pass value.toString("html") from tiny.js to home.js
if this is not possible at least help me integrate both tiny and home components as a single object so that I don't have to pass the value as props to a parent component
import React from "react";
import Tiny from "./tiny";
function Home({ data }) {
const [Questions, setQuestions] = useState();
const [deatils1, setdeatils] = useState();
function clickQuestion() {
axios
.post("https://askover.wixten.com/questionpost", {
Name: Questions,
Summary: deatils1,//pass tiny value as summery
})
.then(() => {
window.location.reload();
});
}
function question(e) {
setQuestions(e.target.value);
}
return (
<>
<div>
<div className="container search-box">
<Form>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control
type="text"
onChange={question}
placeholder="ask anything?"
/>
</Form.Group>
<Tiny /> //tiny component
</Form>
<Button
type="submit"
disabled={!deatils1 || !Questions}
onClick={clickQuestion}
variant="outline-secondary"
id="button-addon2"
>
ask?
</Button>
</div>
</div>
</>
);
}
tiny.js
import React, { useState, useEffect } from "react";
import dynamic from "next/dynamic";
import PropTypes from "prop-types";
//import the component
const RichTextEditor = dynamic(() => import("react-rte"), { ssr: false });
const MyStatefulEditor = ({ onChange }) => {
const [value, setValue] = useState([]);
console.log(value.toString("html"));
useEffect(() => {
const importModule = async () => {
//import module on the client-side to get `createEmptyValue` instead of a component
const module = await import("react-rte");
console.log(module);
setValue(module.createEmptyValue());
};
importModule();
}, []);
const handleOnChange = (value) => {
setValue(value);
if (onChange) {
onChange(value.toString("html"));
}
};
return <RichTextEditor value={value} onChange={handleOnChange} />;
};
MyStatefulEditor.propTypes = {
onChange: PropTypes.func,
};
export default MyStatefulEditor;
Actually, you already have onChange event in tiny, so you only need to pass another onChange event from home to tiny.
import React from "react";
import Tiny from "./tiny";
function Home({ data }) {
const [Questions, setQuestions] = useState();
const [details, setDetails] = useState();
function clickQuestion() {
axios
.post("https://askover.wixten.com/questionpost", {
Name: Questions,
Summary: details,//pass tiny value as summery
})
.then(() => {
window.location.reload();
});
}
function question(e) {
setQuestions(e.target.value);
}
return (
<>
<div>
<div className="container search-box">
<Form>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control
type="text"
onChange={question}
placeholder="ask anything?"
/>
</Form.Group>
<Tiny onChange={(value) => setDetails(value)}/> //tiny component
</Form>
<Button
type="submit"
disabled={!deatils1 || !Questions}
onClick={clickQuestion}
variant="outline-secondary"
id="button-addon2"
>
ask?
</Button>
</div>
</div>
</>
);
}
I am learning Redux. I cannot figure out how to set state.
I need to set state (I'm assuming with useDispatch) by using a login form. On the component Fake1, I am able to console.log the "user" passed with useSelector. If i hardcode a change in state on user.js ({ i.e., username: "beanbag", password: "122345" }), the change in state appears on Fake1, telling me that the mechanics of my setup are good, and that the problem is that state is not being set inside loginOnSubmit().
My code:
const initialStateValue = { username: "", password: "" };
export const userSlice = createSlice({
name: "user",
initialState: { value: initialStateValue },
reducers: {
login: (state, action) => {
state.value = action.payload;
},
logout: (state) => {
state.value = initialStateValue;
},
},
});
export const { login, logout } = userSlice.actions;
export default userSlice.reducer;
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Visibility from "#mui/icons-material/Visibility";
import VisibilityOff from "#mui/icons-material/VisibilityOff";
import InputAdornment from "#mui/material/InputAdornment";
import IconButton from "#mui/material/IconButton";
import Input from "#mui/material/Input";
import Button from "#mui/material/Button";
import LoginIcon from "#mui/icons-material/Login";
import AddCircleOutlineIcon from "#mui/icons-material/AddCircleOutline";
import Stack from "#mui/material/Stack";
import "./LoginForm.css";
import { useDispatch } from "react-redux";
import { login } from "../features/user";
function LoginForm() {
const [user, setUser] = useState(null);
const [loginUsername, setLoginUsername] = useState("");
const [loginError, setLoginError] = useState([]);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [values, setValues] = useState({
password: "",
showPassword: false,
});
const dispatch = useDispatch();
const navigate = useNavigate();
const handleChange = (prop) => (event) => {
setValues({ ...values, [prop]: event.target.value });
};
const handleClickShowPassword = () => {
setValues({
...values,
showPassword: !values.showPassword,
});
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
// useEffect(() => {
// fetch("/authorize_user")
// .then((res) => res.json())
// .then(setUser);
// }, []);
const loginOnSubmit = (e) => {
e.preventDefault();
const newUser = {
username: loginUsername,
password: values.password,
};
// dispatch(login({username: loginUsername, password: values.password}))
fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newUser),
}).then((res) => {
if (res.ok) {
res.json().then((newUser) => {
setUser(newUser);
setIsAuthenticated(true);
setLoginUsername("");
dispatch(login({ newUser }));
navigate("/fake1");
});
} else {
res.json().then((json) => setLoginError(json.error));
}
});
};
const handleSignupRoute = () => {
navigate("/signup");
};
return (
<form onSubmit={loginOnSubmit}>
<div>
<br></br>
<Input
className="test1"
value={loginUsername}
onChange={(e) => setLoginUsername(e.target.value)}
type="text"
label="Username"
placeholder="Username"
/>
<br></br>
<br></br>
<Input
id="standard-adornment-password"
type={values.showPassword ? "text" : "password"}
value={values.password}
// onChange={(e) => setValues(e.target.value)}
onChange={handleChange("password")}
placeholder="Password"
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{values.showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
/>
<br></br>
<br></br>
<br></br>
<div className="test2">
<Stack direction="row" spacing={2}>
<Button
type="submit"
variant="outlined"
endIcon={<LoginIcon />}
className="btn-login"
>
Login
</Button>
<Button
onClick={handleSignupRoute}
variant="outlined"
endIcon={<AddCircleOutlineIcon />}
className="btn-signup"
>
Signup
</Button>
</Stack>
<br></br>
<br></br>
</div>
</div>
</form>
);
}
export default LoginForm;
import React from 'react'
import {useSelector} from 'react-redux'
const Fake1 = () => {
const user = useSelector(state => state.user.value)
console.log(user)
return (
<div>Fake1</div>
)
}
export default Fake1
This question already exists:
return not displaying page data react functional component
Closed 1 year ago.
I have this, my entire react page:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useHistory } from "react-router-dom";
import { useMemo } from "react";
import { connect } from "react-redux";
import AdminNav from "../../../components/admin/AdminNav"
import AdminAboutUsNav from "../../../components/admin/AdminAboutUsNav"
import Header from "../../../components/app/Header";
import { setNavTabValue } from '../../../store/actions/navTab';
import { makeStyles, withStyles } from "#material-ui/core/styles";
import "../../../styles/AddMembershipPage.css";
const AddMembershipPage = (props) => {
const history = useHistory();
const [myData, setMyData] = useState({});
let ssoDetails = {
name: props.blue.preferredFirstName + " " + props.preferredLastName,
email: props.blue.preferredIdentity,
cnum: props.blue.uid,
empType: "part-time"
}
this.state = {
cnum: ssoDetails.cnum,
empType: ssoDetails.empType,
email: ssoDetails.email,
name: ssoDetails.name,
phone: "",
// building: building,
siteList: "",
status: ""
};
const handleInputChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
const handleSubmit = (e) => {
e.preventDefault();
var date = Date().toLocaleString();
const { cnum, empType, email, name, phone, siteList, status } = this.state;
const selections = {
cnum: cnum,
empType: empType,
email: email,
name: name,
phone: phone,
// building: building,
siteList: siteList,
status: status
};
axios
.post("/newMembership", selections)
.then(
() => console.log("updating", selections),
(window.location = "/admin/services")
)
.catch(function (error) {
// alert(error)
window.location = "/admin/services/new";
});
};
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<AdminNav />
{/* <Header title="Services - Admin" /> */}
{/* <AdminAboutUsNav /> */}
<div className="App">
<form onSubmit={this.handleSubmit}>
<h1>Join Us!</h1>
<input value={ssoDetails.name} readOnly name="name" onChange={this.handleInputChange}></input>
<input type="email" value={ssoDetails.email} readOnly name="email" onChange={this.handleInputChange}></input>
<input type="hidden" value={ssoDetails.cnum} readOnly name="cnum" onChange={this.handleInputChange}></input>
<input type="text" value={ssoDetails.empType} readOnly name="empType" onChange={this.handleInputChange}></input>
<input type="text" placeholder="Phone Number" name="phone" onChange={this.handleInputChange}></input>
<input type="text" placeholder="Site List" name="siteList" onChange={this.handleInputChange}></input>
{/* <input type="password" placeholder="Password"></input> */}
<button type="submit">Register</button>
</form>
</div>
</div>
);
}
const mapStateToProps = (state) => {
return {
siteTab: state.siteTab,
blue: state.blue
}
}
const mapDispatchToProps = (dispatch, props) => ({
setNavTabValue: (value) => dispatch(setNavTabValue(value))
});
export default connect(mapStateToProps, mapDispatchToProps)(AddMembershipPage);
however, when I try to run this page, it just shows up blank. It started doing this after I added const handleInputChange, and const handleSubmit to the code. I am basically just trying to submit a form, and it is more complex then I imagined. Before I added those 2 things I just mentioned, the page was working perfectly. but now, I cannot figure it out, and really could use some guidance/help to try to fix this up. any ideas?
It's function component so you don't need to call with this.handleSubmit
Just change it to the onSubmit={handleSubmit}> and onChange={handleInputChange}>
Also remove this.state and use useState instead because this.state was available in class based component not in the function component.
I am trying to write a unit test to the Login component in order to check if handleSubmit function has been called after all the input fields are filled with values.
Here is my Login.js component and my Login.test.js
//Login.js
import React, { useState } from 'react';
import axios from 'axios';
import useStyles from '../styles/LoginStyle';
import { useStatefulFields } from '../../hooks/useStatefulFields';
function Login({ success }) {
const [values, handleChange] = useStatefulFields();
const [error, setError] = useState();
const handleSubmit = async () => {
await axios.post('www.example.com', {values}, {key})
.then((res) => {
if (res.data.success) {
success();
} else {
setError(res.data.error);
}
})
};
return (
<div>
<p className={classes.p}>Personalnummer</p>
<input
type="number"
className={classes.input}
onChange={handleChange}
name="personal_number"
title="personal_number"
/>
<p className={classes.p}>Arbeitsplatz</p>
<input
type="number"
onChange={handleChange}
name="workplace"
title="workplace"
className={classes.input}
/>
<p className={classes.p}>Passwort</p>
<input
type="password"
className={classes.input}
onChange={handleChange}
name="password"
title="password"
/>
<ColorButton
id="login-button"
className={
(values.password && values.personal_number && values.workplace)
? classes.button
: classes.buttonGray
}
disabled={!values.password && !values.personal_number && !values.workplace}
size="large"
onClick={
values.password && values.personal_number && values.workplace
? handleSubmit
: () => {}
}
>
</ColorButton>
</div>
)
}
//Login.test.js
import React from 'react';
import { shallow } from 'enzyme';
import Login from '../components/Workers/Login';
let wrapper;
beforeEach(() => {
wrapper = shallow(<Login success={() => {}} />);
});
test('should call handleSubmit', () => {
const spy = jest.spyOn(wrapper.instance(), 'handleSubmit');
wrapper.find('input[name="workplace"]').simulate('change', { target: { name: 'workplace', value: 'test' } });
wrapper.find('input[name="password"]').simulate('change', { target: { name: 'password', value: 'test' } });
wrapper.find('input[name="personal_number"]').simulate('change', { target: { name: 'personal_number', value: 'test' } });
wrapper.find('#login-button').simulate('click');
expect(spy).toHaveBeenCalled();
});
The error that I am getting is:
TypeError: Cannot read property 'handleSubmit' of null
What am I doing wrong?
I am implementing the Delete function for product item in Firebase by React redux-saga. But I have an issue that the product id to delete has been obtained, but the product has not been removed From Firebase
I do not understand where I am missing
This is my code for product-form
import React, { useState, useEffect } from "react";
import { Form, Container } from "react-bootstrap";
import PropTypes from "prop-types";
import Button from "../../components/Button";
import { CATEGORIES } from "../../constants/categories";
import Loading from "../../components/Loading"
import "../ProductForm/index.css";
const ProductForm = ({
product,
createProductRequest,
fetchProductRequest,
loading,
type }) => {
const [values, setValues] = useState({
image: "",
name: "",
price: 0,
description: "",
categoty: "",
});
const [imageAsFile, setImageAsFile] = useState();
const [isValid, setIsValid] = useState(false);
useEffect(() => {
if (Object.keys(product).length) {
setValues(product);
}
}, [product]);
useEffect(() => {
if (type.CREATE_PRODUCT_SUCCESS) {
fetchProductRequest();
}
}, [fetchProductRequest, type]);
const handleInputChange = (event) => {
// Create new product to update
const newPropdudct = {
...values,
[event.target.name]: event.target.value,
};
// Update new product for value
setValues(newPropdudct);
};
const handleFileChange = (event) => {
const image = event.target.files[0]
setImageAsFile(image)
}
const onHandleSubmit = () => {
if (values.name.trim() === "") {
setIsValid(false);
}
else {
createProductRequest(values, imageAsFile);
}
};
if (loading) {
return (
<Container>
<Loading />
</Container>
);
}
return (
<Container className="product-form">
<Form>
<Form.Group>
<Form.Group>
<Form.File
id="image"
label="Image choose"
value={values.image.name}
onChange={handleFileChange}
/>
</Form.Group>
</Form.Group>
<Form.Group controlId="name">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter product name"
value={values.name}
name="name"
onChange={handleInputChange}
/>
</Form.Group>
<Form.Group controlId="categories">
<Form.Label>Categories</Form.Label>
<Form.Control
as="select"
name="category"
value={values.category}
onChange={handleInputChange}
>
{CATEGORIES.map((category) => (
<option key={category}>{category}</option>
))}
</Form.Control>
</Form.Group>
<Button
btnText="Submit"
size="btn-md"
onClick={onHandleSubmit}
disabled={isValid}
/>
</Form>
</Container>
);
};
export default ProductForm;
This is productAPI which I implement delete from Firebase
import { convertObjectToArray } from "../helpers/product";
import firebaseApp from "./config";
const firebaseDb = firebaseApp.database();
const firebaseStorage = firebaseApp.storage();
/**
* Representation for get list product from firebase
*/
export const onceGetProducts = () =>
firebaseDb
.ref("products")
.once("value")
.then((products) => {
const result = convertObjectToArray(products.val());
return { products: result, status: "ok" };
});
export const deleteProduct = (productId) => {
return firebaseDb.ref('products').child('productId').remove();
}
I already get that Product id, but I cannot delete it from Firebase
I thought I have some missing in productAPI. But I do not know how to resolve it
The button handleDelete function I have imported from another folder. The function implemented by redux-saga.
Anyone have any comment or support for me, I really need your help with this my problem. Thank you so much.
Can you please try the below code
export const deleteProduct = (productId) => {
return firebaseDb.ref('items').child(productId).removeValue();
}