Atlassian React Components - TextField Not Accepted - javascript

I am trying to implement Atlassian React Components in my application.
But TextField is not behaving like normal input text field.
It is not forwarding value while submitting form, and giving warning in console
Warning: styled.input is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
import React, { Component } from 'react';
import { login, resetPassword } from '../helpers/auth';
import TextField from '#atlaskit/field-text';
function setErrorMsg(error) {
return {
loginMessage: error
}
}
export default class Login extends Component {
state = { loginMessage: null }
handleSubmit = (e) => {
e.preventDefault()
login(this.email.value, this.pw.value)
.catch((error) => {
//catch errors
})
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>Email</label>
//THIS TEXTFIELD IS MAKING ISSUE
<TextField autoFocus ref={(email) => this.email = email} placeholder="Email" label="" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" placeholder="Password" ref={(pw) => this.pw = pw} />
</div>
<button type="submit" className="btn btn-primary">Login</button>
</form>
)
}
}

I just faced this problem. To solve it you just need to add prop value="" to your <TextField>

Related

React-hook-form form key value returns undefined after filling inputs and submitting

I'm learning react and I'm having some difficulties. At the moment my question is related to a Login page using ReactJS, Typescript and styled-components. Where I only have the email and password part. I'm manipulating the form with the react hook form, but I have a problem. When I run a console.log of the values ​​of my email and password keys, it just returns undefined. And no error is pointed out in the console.
enter image description here
Here is my code.
import React from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { Form, TitleSecondary } from "./Form.style";
import { Button } from "../Button/Button";
import { InputContainer, InputLabel, InputField } from "./Form.style";
interface IForm {
email: string;
password: string;
}
export const FormLogin = React.forwardRef<HTMLInputElement>(( props, ref) => {
const { register, handleSubmit } = useForm<IForm>();
const onSubmit: SubmitHandler<IForm> = (data) => console.log(data);
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<TitleSecondary>Login</TitleSecondary>
<InputContainer>
<InputLabel htmlFor="email">Email</InputLabel>
<InputField
{...register("email")}
id="email"
type="email"
placeholder=""
ref={ref}
required
/>
</InputContainer>
<InputContainer>
<InputLabel htmlFor="password">Password</InputLabel>
<InputField
{...register("password")}
id="password"
type="password"
placeholder="mail#example.com"
ref={ref}
required
/>
</InputContainer>
<Button />
</Form>
)
})
I confess that I have tried several things since then, but none have been successful.

Is there a way to get a React component's internal values when I click a button on the parent?

Suppose I have a component like this -
const MyForm = ({ formId }) => (
<div>
<input type="text" placeholder="Full name"></input>
<input type="text" placeholder="Email"></input>
</div>
)
export default MyForm;
And then I have my App.js like so -
import React from "react";
import MyForm from "./MyForm";
const App = () => (
<div id="app">
<MyForm formId="formOne"></MyForm>
<MyForm formId="formTwo"></MyForm>
<button onClick={
() => {
// Here, when the user clicks the button,
// I want to get values of both the textboxes,
// from both the component instances
}
}>Submit</button>
</div>
)
export default App;
So basically, what I want is - when the button is clicked, I want to be able to retrieve the values of the textboxes. One way to do this is to raise an event from inside MyForm.js so that every text change is bubbled up to the parent via a callback function prop, but that feels too cumbersome, especially if the form has a lot of fields. Is there any simple or direct way to do this? Do I need to involve global state management tools like Redux?
State inside a component is specific only to that component, the parent , children or sibling of a component have no idea of the state. The only way to communicate the value from one component to another component is via props . In your case, what we need is a state to reside at the App which can then be passed as a prop to both the MyForm Components.
App.js
const [ formState, setFormState ] = useState({ formOne: {fullName: '', Email: ''}, formTwo: '' })
const updateFormValues = (formId, key, value) => {
const stateCopy = JSON.parse(JSON.stringify(formState));
const formToUpdate = stateCopy[formId];
formToUpdate[key] = value;
setFormState(stateCopy)
}
<MyForm formId="formOne" values={formState.formOne} updateFormValues={updateFormValues}></MyForm>
<MyForm formId="formTwo" values={formState.formTwo} updateFormValues={updateFormValues}></MyForm>
MyForm.js
const MyForm = ({ formId, values, updateFormValues }) => {
const onInputChange = (e, key) => {
updateFormValues(formId, key, e.target.value)
}
return(
<div>
<input type="text" onChange={(e) => onInputChange(e, 'fullName'} value={values.fullName} placeholder="Full name"></input>
<input type="text" onChange={(e) => onInputChange(e, 'email'} value={values.email} placeholder="Email"></input>
</div>
)}
export default MyForm;
To have access to data inside children components you need to lift the state to the parent component.
One-way data flow
Identify every component that renders something based on that state.
Find a common owner component (a single component above all the components that need the state in the hierarchy).
Either the common owner or another component higher up in the hierarchy should own the state.
If you can’t find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common owner component.
One way to do this:
import React, { useState } from "react";
function MyForm(props) {
const { handleChange, values } = props;
return (
<div>
<label htmlFor="name">Your name</label>
<input
type="text"
placeholder="Full name"
onChange={handleChange}
value={values.name}
id="name"
name="name"
/>
<label htmlFor="email">Your email</label>
<input
type="email"
placeholder="Email"
onChange={handleChange}
value={values.email}
id="email"
name="email"
/>
</div>
);
}
function App() {
const [values, setValues] = useState({ name: "", email: "" });
const handleChange = (event) => {
const updatedForm = { ...values, [event.target.name]: event.target.value };
setValues(updatedForm);
};
return (
<div id="app">
<MyForm
formId="formOne"
values={values}
handleChange={handleChange}
></MyForm>
<button
onClick={() => {
console.log(values);
}}
>
Submit
</button>
</div>
);
}
export default App;

React Final Form Error: Must specify either a render prop

I am trying to build a simple form with React-Final-Form like this:
import * as React from "react";
import {
PrimaryButton,
} from "office-ui-fabric-react/lib/Button";
import { Form , Field } from "react-final-form";
import { FORM_ERROR } from "final-form";
import { IUserFormValues } from "../../models/user";
import { RootStoreContext } from "../../stores/rootStore";
import TextInputNew from "./TextInputNew";
const NewUIForm = () => {
const rootStore = React.useContext(RootStoreContext);
const { login } = rootStore.userStore;
return (
<Form
onSubmit={(values: IUserFormValues) =>
login(values).catch((error) => ({
[FORM_ERROR]: error,
}))
}
render={({
handleSubmit,
}) => (
<Form onSubmit={handleSubmit}>
<Field name="email" component={TextInputNew} />
<Field name="email" component={TextInputNew} />
<PrimaryButton type='submit' text="Save" />
</Form>
)}
/>
);
};
export default NewUIForm;
The TextInputNew Component is this:
import * as React from "react";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import { FieldRenderProps } from "react-final-form";
interface IProps extends FieldRenderProps<string, HTMLInputElement> {}
const TextInputNew: React.FC<IProps> = ({ input }) => {
return (
<div>
<input {...input} />
<TextField label="Standard" />
</div>
);
};
export default TextInputNew;
Then I got this error when I use this NewUIForm component
Error: Must specify either a render prop, a render function as children, or a component prop to ReactFinalForm
By the way, the UI framework is Fluent-UI
Can anyone help me? Thanks!!
You're second <Form> should be <form>.
<form onSubmit={handleSubmit}>
<Field name="email" component={TextInputNew} />
<Field name="email" component={TextInputNew} />
<PrimaryButton type='submit' text="Save" />
</form>
To anyone else who might encounter this vague error message, the issue is something going wrong in the render function of <Form>.
For OP, it was using the wrong form tag inside of <Form>.
For me, it was a misspelled property on a <Field> component (components={MyComponent}, oops).
Since the error can be caused by any number of reasons and the message wasn't very specific, one can get an idea of where the problem might be via browser debugger, in my case this is what it looked like:

React controlled component error in function component

I am working with forms in React, using function components for the first time. Either I am going crazy, or this should work with no issues...
import React, {useEffect, useState} from 'react';
function ChangePasswordComponent(props) {
const {onChangePassword} = props;
const [isValid, setIsValid] = useState(true);
const [form, setForm] = useState({
password: undefined,
confirm: undefined
})
useEffect(() => {
handleValidation();
}, [form])
function handleValidation() {
setIsValid(form.password === form.confirm);
}
function onFormValueChanges(event) {
setForm({...form, [event.target.name]: event.target.value})
}
function resetFields() {
setForm({
password: undefined,
confirm: undefined
})
}
function onUpdateClick() {
onChangePassword(form.password);
resetFields();
}
return (
<div className="change-password-container">
<input
type="text"
name="password"
value={form.password}
onChange={(event) => onFormValueChanges(event)}
placeholder="new password" />
<input
type="text"
name="confirm"
value={form.confirm}
onChange={(event) => onFormValueChanges(event)}
placeholder="confirm new password" />
{!isValid ?
<span className="validation-error">passwords do not match</span> : null }
<div className="button-container">
<button onClick={() => resetFields()}>Cancel</button>
<button onClick={() => onUpdateClick()}
disabled={!form.password || !isValid}>Update</button>
</div>
</div>
);
}
export default ChangePasswordComponent;
However when I run the code I get an error in console about...
A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
When I look back into the documentation, my pattern seems to follow the Docs just fine. Thoughts?
you should use empty strings like '' instead of undefined.
when your component has first rendered, password and confirm values are undefined. This means that there is no variable to set the value attribute of the input.
Therefore, that error occurs.

React Context API and component methods [duplicate]

This question already has answers here:
Access React Context outside of render function
(5 answers)
Closed 3 years ago.
I've followed a few online examples, where they have a counter and an increment function in Context, and on a distant component, call the increment method and the results shows. All great, but ... I am trying to expand on this and create a login box, that sets an isAthenticated flag.
I have a very basic context:
import React from 'react';
const Context = React.createContext();
export class Provider extends React.Component {
state = {
isAuthenticated: false,
user: {
name: "Craig",
email: "craig#here.com"
},
changeEmail: (newEmail) => {
let user = this.state.user;
user.email = newEmail;
console.log(user);
this.setState({ user: user})
},
changeAuthenticated: () => {
this.setState ({ isAuthenticated: !this.state.isAuthenticated });
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer;
In it I allow the user to change email, and change isAuthenticated state.
My component (Remove style stuff) looks like this:
import React from 'react';
import { Input, Label, Button, Container } from 'reactstrap';
import { Consumer } from '../context';
class Login extends React.Component {
render() {
return (
<Consumer>
{value => {
return (
<Container style={containerStyle} >
<div style={loginBoxStyle}>
<div>
<h3>Login</h3>
</div>
<div style={loginBoxFieldsStyle}>
<div style={loginBoxFieldStyle}>
<div style={loginBoxLabelStyle}>
<Label for="email">Email:</Label>
</div>
<div style={loginBoxLabelStyle}>
<Input type="email" name="email" id="email" placeholder="Your Email" value={value.user.email} onChange={e=>value.changeEmail(e.target.value)} />
</div>
</div>
</div>
<div style={loginBoxFieldsStyle}>
<div style={loginBoxFieldStyle}>
<div style={loginBoxLabelStyle}>
<Label for="password">Password:</Label>
</div>
<div style={loginBoxLabelStyle}>
<Input type="password" name="password" id="password" placeholder="Your Password" />
</div>
</div>
</div>
<div style={loginBoxButtonStyle}>
<Button color="info" onClick={value.changeAuthenticated}>Login</Button>
</div>
</div>
</Container>
)}
}
</Consumer>
)
}
}
export default Login;
So when I change the email, the Context state is updated. And when I click the Login button, for now, it simply toggles IsAuthenticated.
I don't want the state to update as I type in the email box. I'd prefer to update the state when the Login button is clicked. So I feel I need a local component state, or something, which updates that state when I edit the data in the text boxes. And then updates the Context when I click Login.
But... How do I set up the state? 'values' (from context) is only available inside the Render. I need to set my component state outside of the render. So how would I go about achieving this?
My login button onClick should also fire a local method which has all the validation etc, and then update my route to redirect to a page on success. But then it needs access to the Context.UpdateMethod - from outside of the tags. Not sure how to achieve this.
You should probably just create a sub-component and then use the props to initialize the state.
class Login extends React.Component {
render() {
return (
<Consumer>
{value => (
<Container style={containerStyle}>
<SubComponent
changeAuthenticated={value.changeAuthenticated}
// ...etc

Categories

Resources