Handling action in Remix.run without POST - javascript

I read up on the Remix docs on action and most of information I can find on action is it uses the the form POST with button submit to trigger the action
export default function Game() {
const counter = useLoaderData();
return (
<>
<div>{counter}</div>
<div>
<Form method="post">
<button type="submit">click</button>
</Form>
</div>
</>
);
}
However, how would the action be triggered in regards to something else like... drag and drop components, where after dropping it should trigger the action post

useSubmit should do what you want.
An example from the docs
import { useSubmit, useTransition } from "remix";
export async function loader() {
await getUserPreferences();
}
export async function action({ request }) {
await updatePreferences(await request.formData());
return redirect("/prefs");
}
function UserPreferences() {
const submit = useSubmit();
const transition = useTransition();
function handleChange(event) {
submit(event.currentTarget, { replace: true });
}
return (
<Form method="post" onChange={handleChange}>
<label>
<input type="checkbox" name="darkMode" value="on" />{" "}
Dark Mode
</label>
{transition.state === "submitting" ? (
<p>Saving...</p>
) : null}
</Form>
);
}

Related

How to change the url for signin page in next-auth?

In Next.js project I've implemented authentication with Next-Auth.
In index.js (as the Next-Auth documentation explains) I return a User only if there is a session
export default function Home({characters}) {
const {data: session} = useSession()
return (
<>
<Meta
description="Generated by create next app"
title={!session ? "Home - Login" : `Home - ${session.user.name}`}
/>
{session ? <User session={session} /> : <Guest/>}
</>
)
}
In the Guest component I have a Sign In button, and the onClick event points to the signIn method from "next-auth/react"
function Guest() {
return <Layout className="flex flex-col h-screen">
<div className="font-extrabold mb-4 text-3xl">GUEST USER</div>
<Button onClick={() => signIn()}>Sign In</Button>
</Layout>
}
as soon as I click that button I'm redirected to this pages/auth/signin.js page.
This is the page where I can login through EmailProvider or GoogleProvider
import { getCsrfToken, getProviders, signIn } from "next-auth/react"
import { Meta, Layout, Card, InputGroup, Button } from "../../components/ui";
export default function SignIn({ csrfToken, providers }) {
return (
<Layout>
<Meta title="Login"/>
<Card>
<form method="post" action="/api/auth/signin/email">
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<InputGroup
type="email"
htmlFor="email"
label="Email"
name="email"
/>
<Button type="submit">Sign in with Email</Button>
</form>
{Object.values(providers).map((provider) => {
if(provider.name === "Email") {
return
}
return (<div className="mt-3" key={provider.name}>
<Button onClick={() => signIn(provider.id)}>
Sign in with {provider.name}
</Button>
</div>)
})}
</Card>
</Layout>
)
}
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken(context)
const providers = await getProviders()
return {
props: { csrfToken, providers },
}
}
When I'm in this page the url is http://localhost:3000/auth/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000
I wanna know if it's possible to change that url to a more polite one like http://localhost:3000/login or something like this.
This page is already a custom login page as you can see in my [...nextauth].js
pages: {
signIn: '/auth/signin',
},
any suggestions? Thanks guys!
Yes it should work. Lets say you put this in your [...nextauth].js options
pages: {
signIn: '/login'
}
The signIn button will now redirect to /login.
Then you just have to put your login page under pages: pages/login.js.

onClick function is not called after I have enabled the button in Reactjs

I have a textarea and a button. The button is disabled by default and when the user starts typing, I enable the button to be clicked. But the problem is that, the onClick function is not called while already disabled = false was set.
I've seen this: button onClick doesn't work when disabled=True is initialized (Reactjs)
Seems to be a good idea, but after I setState with the new value, my component is re-rendering, and I don't really want that.
const refText = useRef(null);
const refBtn = useRef(null);
function handleBtnStatus(e) {
let text = e.target.value;
if(text.replace(/\s/g, "").length > 0) {
refBtn.current.disabled = false;
}
else {
refBtn.current.disabled = true;
}
}
function postThis() {
console.log("You posted! Text:", refText.current.value);
// disable again
refBtn.current.disabled = true;
// delete previous text wrote
refText.current.value = "";
}
return (
<>
{isLogged && (
<div className="container">
<div className="content">
<div className="utool-item-text">
<textarea name="textArea" placeholder="Write something.." ref={refText} onChange={(e) => handleBtnStatus(e)}></textarea>
</div>
<div className="utool-item-post">
<button className="ust-btn-post" ref={refBtn} disabled={true} onClick={postThis}>Da Tweet</button>
</div>
</div>
<div className="posts-section">
<div className="list-posts">
{posts.map((p) => {
return (p.hidden === false ? (
<div className="post" key={p.id}>
<div className="post-text">
<span>{p.text}</span>
</div>
</div>
) : (''))
})}
</div>
</div>
</div>
)}
</>
)
Any help?
Use state instead of refs, re-rendering is ok for your case
Simplified example:
import React, { useState } from 'react';
const SimpleExample = () => {
const [textAreaValue, setTextAreaValue] = useState('');
return (
<>
<button disabled={!textAreaValue} onClick={() => console.log('onClick handler')}>
click me
</button>
<textarea value={textAreaValue} onChange={(e) => setTextAreaValue(e.target.value)} />
</>
);
};
And I would recommend checking this Use state or refs in React.js form components?

I want to make a situation whereby if i click the back button, it reverses the whole function

The code
const DEFAULT_IS_CLICKED = false;
function RightBody() {
const [isClickedYes, setIsClickedYes] = React.useState(DEFAULT_IS_CLICKED);
const onClickYes = () => {
setIsClickedYes(true);
};
return (
<Card>
<SmallCircle />
<Div>
<CardContent number={"1."} title={"Course of study in school:"} />
<CardContent number={"2."} title={"Are you a student?"} />
<div>
//comment : i want when i click on the ReturnBtn some lines below this, it reverses the whole is clicked and i cant seem to figure it out
{isClickedYes ? (
<InputCont>
<TickImg src={ticked} />
<Tick>Yes</Tick>
<Input1 name="text" placeholder="course studied in school" />
<Input2
type="text"
onFocus={(e) => {
e.currentTarget.type = "date";
e.currentTarget.focus();
}}
placeholder="Expected graduation date"
/>
<ReturnBtn src={back} />
</InputCont>
) : (
<Button1 onClickYes={onClickYes} />
)}
</div>
<Sec1>
<CardContent number={"3."} title={"Did you graduate?"} />
<Button2 />
</Sec1>
<Sec2>
<CardContent number={"4."} title={"Did you graduate?"} />
<Button3 />
</Sec2>
</Div>
</Card>
);
}
export default RightBody;
i want to do a function that when i click on the ReturnBtn it brings me back to this where i had just two bbuttons, please help
function Button1({ onClickYes }) {
return (
<div className="buttons">
<button onClick={onClickYes}>yes</button>
<button>No</button>
</div>
);
}
the original default mode of the code is two buttons, Yes and No but when i click on yes then it >takes me to where i ve that input field and then the return icon(ReturnBtn). My aim is that whenever the ReturnBtn is clicked, it does like a reverse and takes me back to the default state where my two buttons, Yes and No comes bac
I imagine the code for ReturnBtn looks like this:
function ReturnBtn({src}) {
return (
<button>Text Goes Here</button>
)
}
You should make it modify the same state that initially makes the buttons disappear. So add the following function in RightBody.
function RightBody() {
const [isClickedYes, setIsClickedYes] = React.useState(DEFAULT_IS_CLICKED);
const onClickYes = () => {
setIsClickedYes(true);
};
const onClickReturn = () => {
setIsClickedYes(false);
}
...
return (
...
<ReturnBtn src={back} onClick={onClickReturn} />
...
)
}
Then don't forget to attach the on click handler to the button itself inside of ReturnBtn
function ReturnBtn({src, onClick}) {
return (
<button onClick={onClick}>Text Goes Here</button>
)
}
At this point, I would also update setIsClickedYes to have a more descriptive name.
use the NOT operator for your onClickYes function, that should help you toggle the state mode
const onClickYes = () => { setIsClickedYes(!isClickedYes) }

how to change an UseStatus targeting an axios post reponse?

I'm back once more with something that has been breaking my head today.
so I'm making a contact form is almost done except for an animation I want to include that comes in three steps.
1- prompting the user to contact
2-making the waiting for the user-friendlier with a small loader
3-showing either everything went good and the form was sent or something went wrong
so my idea to accomplish this was to use three different icons/loaders and position all of them on top of each other and make them visible or hide them as necessary using UseState.
for now, I can hide the first icon(from step one) as soon as the submit button is clicked, but I haven't been able to make appear the loader or as the API completes the response the last icon
wondering if I should access it any other way?
import styled from "styled-components";
import { RiMailSendFill,FcApproval } from 'react-icons/all';
import '../../Style/styleComponents/Style.css';
import {sendMessage} from '../../Actions/msgAction';
import { useDispatch, useSelector } from 'react-redux';
import { useForm } from "../../Hook/useForm";
const ContactForm = () => {
const dispatch = useDispatch();
const initFormValues =
{
nombre : "nico ",
email : "sasjaja#asdsa ",
telefono : "asda ",
empresa : "dasd",
mensaje : "dasdas",
date: "s"
}
const[formValues, handleInputChange, reset] = useForm(initFormValues);
const{nombre, email, telefono, empresa, mensaje} = formValues
//loader submit buttons
const[mail, setMail]= useState(true);
const[loading, setLoading]= useState(false);
const[approved, setApproved]= useState(false);
const handleSendMsg = ( event ) =>
{
event.preventDefault();
dispatch( sendMessage( formValues ) )
.then( ( result ) =>
{
if( result )
{
console.log(initFormValues);
//closeModal();
console.log('dat')
};
setLoading(true);
});
reset();
}
const showE =()=> {
if (mail) {
setMail(false)
setLoading(true)
console.log("pressed submit");
}
}
const showL=()=>{
if (loading) {
setLoading(false)
console.log("sending email ");
}
}
return (
<Container>
<Left>
<h1>Tráenos tus desafíos</h1>
</Left>
<Right>
<form onSubmit={ handleSendMsg }>
<Label>
<Linput>
<Name>
<label htmlFor="name">Nombre:</label>
<input type="text" id="name" required name="nombre" value={ nombre } onChange={ handleInputChange } />
</Name>
<Tel>
<label htmlFor="name">Telefono:</label>
<input type="text" id="phone" required name="telefono" value={ telefono } onChange={ handleInputChange } />
</Tel>
<Company>
<label htmlFor="company">Empresa:</label>
<input type="text" id="company" name="empresa" value={ empresa} onChange={ handleInputChange }/>
</Company>
</Linput>
<Rinput>
<Email>
<label htmlFor="email">E-mail:</label>
<input type="email" id="email" required name="email" value={ email } onChange={ handleInputChange }/>
</Email>
<Msg>
<label htmlFor="message">Mensaje:</label>
<textarea id="message" required name="mensaje" rows="8" cols="50" value={ mensaje } className="bigger" onChange={ handleInputChange }/>
</Msg>
</Rinput>
</Label>
<Button>
<Send>
<button type="Submit" id ="submit" onClick={showE, showL}>Enviar</button>
</Send>
<Sent>
<RiMailSendFill id="mail" className={ mail ? 'svg': "svg active"}/>
<Loader className={ loading ? 'spin': "spin active"}>
<div class="spin"></div>
</Loader>
{/* <FcApproval id= "approve" className={ approved ? 'approve': "approve active"}/> */}
</Sent>
</Button>
</form>
</Right>
</Container>
);
};
export default ContactForm;
thanks, yall always saving me!
There are ways to make states work with each other easiest way is like this.
1-useStates for each of the
elements you want to be able to switch states to.
const [mail, setMail] = useState(true);
const [approved, setApproved] = useState(false);
2 Main function with smaller functions,
for each one to change accordingly.
function showL( ){
setMail(false);
if(!mail){
return setApproved(true);
}
}
//hide mailIcon / show approve
function showA( ){
setApproved(true);
if(approved){
return setMail(false);
}
}
add an event listener to the specific
the element you will work with to trigger the changes,
here you pass the two functions like this.
<Button>
<Send>
<button type="Submit" id="submit" onClick={() => {showL(); showA();}}>
Enviar
</button>
</Send>
TERNARY EXPRESION if true, render element and false null
<Sent>
<EMail>
{mail ? <RiMailSendFill/> : null}
</EMail>
<Loader>
{approved ? <FcApproval/>: null}
</Loader>
</Sent>
</Button>```

Conditional rendering on select

I am pretty new to the wonderful world of React.
I have two inputs passing data through from an API that renders a list of options. And I want to send the selected inputs from those options back to the parent in the input fields to display for another search.
I have tried passing state down to them and render them them optionally with both a ternary and an if else statement in the "SearchCityList" component in several ways but I either get both lists rendered and they would have to choose between one list that is doubled to put in each input field or it only puts the selected value in one input. Would appreciate any & all suggestions Thanks!
class Form extends Component {
state = {
showComponent: false,
showComponent2: false,
};
// open/close control over SearchCity component box
openSearch = () => {
this.setState({ showComponent: true });
};
openSearch2 = () => {
this.setState({ showComponent2: true });
};
closeSearch = () => {
this.setState({
showComponent: false,
showComponent2: false
});
};
// Passed down cb function to get selected city search in selectCity component
GoingTo = (flights) => {
this.setState({ GoingTo: [flights] });
};
LeavingFrom = (flights) => {
this.setState({ LeavingFrom: [flights] });
};
render() {
return (
<div>
<form className="form-fields container">
<div className="inputs">
<h1>Search for a flight!</h1>
<div className="depart">
<input
onClick={this.openSearch}
className="flight-search"
placeholder="Leaving From"
value={this.state.LeavingFrom}
></input>
<input type="date"></input>
</div>
<div className="Returning">
<input
onClick={this.openSearch2}
className="flight-search"
placeholder="Going To "
value={this.state.GoingTo}
></input>
<input type="date" placeholder="Returning"></input>
</div>
</div>
<button>Check Flights!</button>
</form>
{this.state.showComponent || this.state.showComponent2 ? (
<SearchCity
openSearch={this.openSearch}
openSearch2={this.openSearch2}
flightSearch={this.state.flightSearch}
closeSearch={this.closeSearch}
GoingTo={this.GoingTo}
LeavingFrom={this.LeavingFrom}
onSearchSubmission={this.onSearchSubmission}
closeSearch={this.closeSearch}
/>
) : null}
</div>
);
}
}
export default Form;
class SearchCity extends Component {
state = {
LeavingFrom: "",
GoingTo: "",
search: "",
flightSearch: [],
};
// Search submission / api call
onSearchSubmission = async (search) => {
const response = await Axios.get(
{
headers: {
"
useQueryString: true,
},
}
);
// set New state with array of searched flight data sent to searchCity component
const flightSearch = this.setState({ flightSearch: response.data.Places });
};
// Callback function to send search/input to parent "Form" component
submitSearch = (e) => {
e.preventDefault();
this.onSearchSubmission(this.state.search);
};
// closeSearch callback function sent from Form component to close pop up search box when X is pressed
closeSearch = () => {
this.props.closeSearch();
};
render() {
return (
<div className="container search-list">
<form onChange={this.submitSearch}>
<i className="fas fa-times close-btn" onClick={this.closeSearch}></i>
<input
onChange={(e) => this.setState({ search: e.target.value })} //query-search api
value={this.state.search}
className="search-input"
type="text"
placeholder="Search Locations"
></input>
<div className="search-scroll">
<SearchCityList
openSearch={this.props.openSearch}
openSearch2={this.props.openSearch2}
LeavingFrom={this.props.LeavingFrom}
GoingTo={this.props.GoingTo}
flightSearch={this.state.flightSearch}
/>
</div>
</form>
</div>
);
}
}
export default SearchCity;
function SearchCityList({ flightSearch, LeavingFrom, GoingTo }) {
const renderList = flightSearch.map((flights) => {
return (
<div>
<SelectCityLeaving LeavingFrom={LeavingFrom} flights={flights} />
<SelectCityGoing GoingTo={GoingTo} flights={flights} />
</div>
);
});
return <div>{renderList}</div>;
}
export default SearchCityList;
First of all, when dealing with state, make sure you initialize in the constructor and also ensure you bind your handlers to this component instance as this will refer to something else in the handlers if you don't and you won't be able to call this.setState().
constructor(props) {
super(props); // important
state = {
// your state
};
// make sure to bind the handlers so `this` refers to the
// component like so
this.openSearch = this.openSearch.bind(this);
}

Categories

Resources