How to get form data onSubmission in React-remix by using useFetcher Hook using fetcher.submit() - remix

I have a simple component with an input field and a submit button. I just want to get my data after i fill the input field and submit the form. by using useFetcher hook and fetcher.submit().
import { useEffect } from 'react';
import { useFetcher } from '#remix-run/react'
import { ActionFunction } from '#remix-run/node';
function fetchHook() {
const fetch = useFetcher();
useEffect(() => {
console.log("useEffect");
}, []);
return (
<div>
<h1> Use Fetcher Hook</h1>
<fetch.Form action='/fetcher' method='post'>
<div>
<input type="text" name="name" id="" />
<button type='submit' > Submit</button>
</div>
</fetch.Form>
</div>
)
}
export default fetchHook;
export const action: ActionFunction = async ({ request }) => {
}
What changes should i make to get my desired result. I am new to react-remix.

Related

Nextjs: Cant render a component while using map over a array of objects. Objects are not valid as a React child

I dont know why when i want to render a component inside of a map function, basiclly i have a List component, and when i fetch data from an API with the email, etc.. from users i want that component to render that info. But i get the following error:
Unhandled Runtime Error
Error: Objects are not valid as a React child (found: object with keys {email, phone, nick}). If you meant to render a collection of children, use an array instead.
My List component looks like this:
import React from 'react'
export default function List(email, nick, phone) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email}</p>
<strong>Nick: </strong>
<p>{nick}</p>
<strong>Phone: </strong>
<p>{phone}</p>
</div>
)
}
And my List user page looks like this:
import React from 'react'
import Nav from '../../components/Nav/Nav'
import { useEffect, useState } from 'react';
import List from '../../components/User/List';
export default function index() {
const [users, setUsers] = useState([])
const fetchUsers = async () => {
const response = await fetch("http://localhost:3001/api/internal/users");
const data = await response.json();
console.log(data["data"])
setUsers(data["data"])
}
useEffect(() => {
fetchUsers()
}, [])
return (
<div>
<Nav />
{users.map(user => (
<List
email={user.attributes.email}
phone={user.attributes.phone}
nick={user.attributes.nick}
/>
))}
</div>
)
}
UPDATE 21 ABR
For some reason when i do this :
export default function List(email, phone, nick) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email.email}</p>
<strong>Nick: </strong>
<p>{email.phone}</p>
<strong>Phone: </strong>
<p>{email.nick}</p>
</div>
)
}
It works... Someone knows what it can be?
You are passing the props in a wrong way. Either use it as a single object in props or have all the props it inside {} using destructuring method.
export default function List({email, phone, nick}) {}
OR
export default function List(props) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{props.email}</p>
<strong>Nick: </strong>
<p>{props.phone}</p>
<strong>Phone: </strong>
<p>{props.nick}</p>
</div>
)
}

React component data not saved when submit

Below is my code, the React app is connected to Node js and the data of comment are saved when submit but it's not working for StarRating component.
The comment data is saved in the db table but not the rating
Please pass setRating in starComponent as props
Like below:
<StarRating rating={rating1} updateRating={(e) => setRating1(e)}
onChange={e => setRating1(e.target.value)}></StarRating>
Now you will get updateRating as props in starComponent. So update rating form star component like below:
import React, { useState} from "react";
import { FaStar } from 'react-icons/fa';
const StarRating = ({rating, updateRating}) =>{ // Here you will get setRating state(State of app component) in props
// const [rating, setRating] = useState(null); // not needed this state here. Update rating value in state which comes form props
const [hover, setHover] = useState(null);
return <div>
<p>Rate your experience from 0 to 5 stars</p>
{[... Array(5)].map((star, i)=>{
const ratingValue= i + 1;
return (
<label>
<input
type="radio"
name="rating"
value={rating}
onClick={() =>updateRating(ratingValue)} /> // Update `updateRating` state which comes from app component.
<FaStar
className="star"
color={ratingValue <= (hover || rating) ? "#11C4B0" : "#D3D3D3"}
size={40}
onMouseEnter={() =>setHover(ratingValue)}
onMouseLeave={() =>setHover(null)}
/>
</label>
);
})}
</div>
}
export default StarRating;
You will get updated state in rating1 in app component if any changes occurred from starComponent.
I think the Problem is that you are accessing the rating state in App component but the real state with the value is the rating state of StarRating component. Also, you have passed the props onChange and value to StarRating component but The Props concept is different than the HTML Attributes concept so you definitely need to look into that. Anyway, the possible Solution can be...
import * as React from 'react';
import './App.css';
import StarRating from './StarRating';
import StarRating2 from './StarRating2';
import StarRating3 from './StarRating3';
import { TextArea } from 'semantic-ui-react';
import AlertDialogSlide from './confirmation';
import Dialog from '#mui/material/Dialog';
import DialogActions from '#mui/material/DialogActions';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import Slide from '#mui/material/Slide';
import Button from '#mui/material/Button';
import { useState } from "react";
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
function App() {
const [open, setOpen] = React.useState(false);
const [comment, setComment] = useState("");
const [rating1, setRating1] = useState("");
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const onSubmitForm = async e => {
e.preventDefault();
try {
const body = { rating1, comment };
const response = await fetch("http://localhost:5000/feedback", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
window.location = "/";
} catch (err) {
console.error(err.message);
}
};
return (
<form onSubmit={onSubmitForm} >
<div className="App">
<img src='solavievelogo.png'></img>
<hr/>
<h2>Leave a feedback!</h2>
<StarRating setRating={setRating1} />
<hr2/>
<StarRating2></StarRating2>
<hr2/>
<StarRating3></StarRating3>
<hr2/>
<p>Please leave a comment about your experience below:</p>
<TextArea placeholder=' Type your comment here...'
value={comment}
onChange={e => setComment(e.target.value)}
></TextArea>
<br/>
<button class="Button" type='submit' variant="outlined" onClick={handleClickOpen}><span class="Button-inner">SEND FEEDBACK</span> </button>
<Dialog
open={open}
TransitionComponent={Transition}
keepMounted
onClose={handleClose}
aria-describedby="alert-dialog-slide-description"
>
<DialogContent>
<img src='confirm.png'></img>
<DialogContentText id="alert-dialog-slide-description">
<p>Thank you for your message!</p>
<p> We will be in contact soon..</p>
</DialogContentText>
</DialogContent>
<DialogActions >
<button class="Button" type='submit' onClick={handleClose} ><span class="Button-inner">Close</span> </button>
</DialogActions>
</Dialog>
</div>
</form>
);
}
export default App;
StarRating Component
import React, { useState} from "react";
import { FaStar } from 'react-icons/fa';
const StarRating = ({setRating}) =>{
const [hover, setHover] = useState(null);
return <div>
<p>Rate your experience from 0 to 5 stars</p>
{[... Array(5)].map((star, i)=>{
const ratingValue= i + 1;
return (
<label>
<input
type="radio"
name="rating"
value={ratingValue}
onClick={() =>setRating(ratingValue)} />
<FaStar
className="star"
color={ratingValue <= (hover || rating) ? "#11C4B0" : "#D3D3D3"}
size={40}
onMouseEnter={() =>setHover(ratingValue)}
onMouseLeave={() =>setHover(null)}
/>
</label>
);
})}
</div>
}
export default StarRating;

"Expected `onClick` listener to be a function, instead got a value of `string` type (ReactJS/MaterialUI)

I create a login button that onClick logs the user in and then the generated information is stored in the local storage, but I keep getting an "Expected onClick listener to be a function, instead got a value of string type. I am using reactJS to do so.
// Global Navigation Bar
import { connect } from "react-redux";
import React, { Component } from "react";
import cognitoUtils from "lib/cognitoUtils";
import "assets/css/Base.css";
import Avatar from "#material-ui/core/Avatar";
import Tooltip from "#material-ui/core/Tooltip";
import AccountCircleOutlinedIcon from "#material-ui/icons/AccountCircleOutlined";
import AccountCircleIcon from "#material-ui/icons/AccountCircle";
const mapStateToProps = state => {
return { session: state.session };
};
class SignInOut extends Component {
onSignOut = e => {
e.preventDefault();
cognitoUtils.signOutCognitoSession();
};
state = {
on: true
};
toggle = () => {
this.setState({
on: !this.state.on
});
};
render() {
return (
<div>
<button className="profile_button" onClick={this.toggle}>
{this.state.on && (
<div>
{this.props.session.isLoggedIn ? (
<div>
<a
className="Home-link"
href="/home"
onClick={this.onSignOut}
>
<Tooltip title="Profile">
<Avatar className="profile_icon">
<AccountCircleIcon className="profile_icon_in" />
</Avatar>
</Tooltip>
</a>
</div>
) : (
<div>
<a
className="Home-link"
href={cognitoUtils.getCognitoSignInUri()}
onClick="/home"
>
<Tooltip title="Profile">
<Avatar className="profile_icon">
<AccountCircleOutlinedIcon className="profile_icon" />
</Avatar>
</Tooltip>
</a>
</div>
)}
</div>
)}
</button>
</div>
);
}
}
export default connect(mapStateToProps)(SignInOut);
Because you are passing String type to onClick
onClick="/home"
You need to pass a function as stated in the error. something like you did before
onClick={this.onSignOut}

How do I use properly PropTypes on React 15.6.0?

I'm starting to work with react and redux, but I'm still a little lost about how to handle props and states.
I'm getting this type error:
TypeError: Cannot read property 'touched' of undefined
{name.touched && name.error && <div className="EmployeeForm-error">{name.error}</div>}
Could someone point me in the right direction or make me know what I'm doing wrong
EmployeeFormComponent.js:
import React from 'react';
import { reduxForm } from 'redux-form';
const EmployeeForm = ({ addEmployee, fields: {name}, handleSubmit }) => {
return (
<form onSubmit={handleSubmit(addEmployee)} >
<div>
<input
type="text"
placeholder="Name"
{...name}
/>
{name.touched && name.error && <div className="EmployeeForm-error">{name.error}</div>}
</div>
...
</form>
);}
export default reduxForm({
form: 'employee',
fields: ['name'],
validate,
})(EmployeeForm);
EmployeeFormContainer.js
import { connect } from 'react-redux';
import EmployeeForm from './EmployeeFormComponent';
import React from 'react';
class EmployeeFormContainer extends React.Component {
render() {
return (
<EmployeeForm {...this.props}/>
)
}
}
To solve it I modified a little my previous changing it to this, now I'm using redux-form Field, and sending the input on component attribute.
import React from 'react';
import { Field, reduxForm } from 'redux-form';
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div>
<input {...input} placeholder={label} type={type}/>
{touched && error && <div className="EmployeeForm-error">{error}</div>}
</div>
)
const EmployeeForm = ({ addEmployee, fields: { name, surname}, handleSubmit }) => {
return (
<form onSubmit={handleSubmit(addEmployee)}>
<div>
<Field name="name" type="text" component={renderField} label="name"/>
</div>
...
</form>
);}

Enabling submit button button when all inputs is filled?

Entire examples doesn't show simple solution how to keep submit button disabled until all fields is filled up in redux-form.
I tried to use this approach (TypeScript):
import * as React from 'react';
import * as reduxForm from 'redux-form';
export interface Props extends reduxForm.InjectedFormProps {}
let passedUsername = false;
let passedPassword = false;
const required = (value: string, callback: (passed: boolean) => void) => {
console.info(`PERFORM REQUIRED FIELD CHECK FOR ${value}`);
if (value && value.trim().length > 0) {
callback(true);
} else {
callback(false);
}
};
const usernameRequired = (value: string) => {
required(value, passed => { passedUsername = passed; });
};
const passwordRequired = (value: string) => {
required(value, passed => { passedPassword = passed; });
};
const isPassed = () => {
console.info(`USER PASSED: ${passedUsername}`);
console.info(`PASSWORD PASSED: ${passedPassword}`);
const result = passedUsername && passedPassword;
console.info(`PASSED: ${result}`);
return result;
};
const LoginForm = ({handleSubmit, pristine, submitting}: Props) => (
<form onSubmit={handleSubmit}>
<div>
<label>Username </label>
<reduxForm.Field
name="username"
component="input"
type="text"
validate={[usernameRequired]}
placeholder="Username"
/>
<br/>
<label>Password </label>
<reduxForm.Field
name="password"
component="input"
type="password"
validate={[passwordRequired]}
placeholder="Password"
/>
</div>
<br/>
<div>
<button type="submit" disabled={!isPassed()}>
<i className="fa fa-spinner fa-spin" style={{visibility: (submitting) ? 'visible' : 'hidden'}}/>
<strong>Login</strong>
</button>
</div>
</form>
);
export default reduxForm.reduxForm({
form: 'login'
})(LoginForm);
But this code above doesn't seems to be working. The form doesn't want to re-render even if I force it through subscribe event. It only re-render when pristine or submitting event is triggered. But if I want to re-render myself the form just ignore it. Maybe some flag I missed to re-render manually the form when I need to?
Ok, finally the solution has been found: just need to modify parameter pure in reduxForm constructor from true (default) to false
export default reduxForm.reduxForm({
form: 'login',
pure: false
})(LoginForm);
And the from will re-render whenever you need.

Resources