I use react-select and I'm new.I have a component called Example that executes the handleChange method correctly
const colourOptions = [
{ value: '1', label: '1', color: '#00B8D9' },
{ value: '2', label: '2', color: '#0052CC' },
{ value: '3', label: '3', color: '#5243AA' },
];
class Example extends React.Component {
state = {
selectedOption: null,
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
console.log(selectedOption)
}
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={colourOptions}
/>
);
}
}
export default Example;
In another file we have a button
export default function UserProfile() {
return (
<div>
<Example1/>
<Example2/>
<Example3/>
<Button type="Submit">Search</Button>
</div>
);
}
How can I display the value of selectedOption by clicking on the button?
The correct way is to maintain the selectedOption and the handleChange in the parent(UserProfile) and pass them down to the child(Example).
UserProfile Component
export default function UserProfile() {
const [selectedOption, setSelectedOption] = useState({});
const handleChange = (selectedOption) => {
setSelectedOption(selectedOption)
console.log(selectedOption)
};
const handleClick = () => {
console.log(selectedOption);
};
return (
<div>
<Example onHandleChange={handleChange} selectedOption={selectedOption}/>
<Button onClick={handleClick} type="Submit">Search</Button>
</div>
);
}
Example Component
class Example extends React.Component {
render() {
const { selectedOption, onHandleChange } = this.props;
return (
<Select
value={selectedOption}
onChange={onHandleChange}
options={colourOptions}
/>
);
}
}
export default Example;
Related
I have a container component that works with Redux, in it I determined the state of the text field and throw it into the form component that works with Formik
But I have such a problem that after clicking the button, the text field is not cleared
How do I fix this ? I've seen a lot about resetForm() from Formik, but I can't work with it
TaskInput.jsx
export const TaskInput = ({ value, onChange, onAdd }) => {
const formik = useFormik({
initialValues: {
text: value,
},
})
return (
<Container>
<Formik>
<FormWrapper onSubmit={onAdd}>
<Input
id="task"
type="text"
placeholder="Add a task"
value={formik.text}
onChange={onChange}
/>
<AddButton type="submit">Add</AddButton>
</FormWrapper>
</Formik>
</Container>
)
}
Task.jsx(component container)
class Task extends PureComponent {
constructor(props) {
super(props)
this.state = {
taskText: '',
}
}
handleInputChange = e => {
this.setState({
taskText: e.target.value,
})
}
handleAddTask = () => {
const { taskText } = this.state
const { addTask } = this.props
addTask(uuidv4(), taskText, false)
this.setState({
taskText: '',
})
}
render() {
const { taskText } = this.state
return (
<>
<TaskInput
onAdd={this.handleAddTask}
onChange={this.handleInputChange}
value={taskText}
/>
...
</>
)
}
}
const mapStateToProps = ({ tasks }) => {
return {
tasks,
}
}
export default connect(mapStateToProps, {
addTask,
removeTask,
completeTask,
editTask,
})(Task)
Solution
export const TaskInput = ({ value, onChange, onAdd }) => {
const inputRef = useRef(null)
const formik = useFormik({
initialValues: {
text: value,
},
})
const onSubmit = () => {
onAdd(),
inputRef.current.value = ''
}
return (
<Container>
<Formik>
<FormWrapper onSubmit={onSubmit}>
<Input
ref={inputRef}
id="task"
type="text"
placeholder="Add a task"
value={formik.text}
onChange={onChange}
/>
<AddButton type="submit">Add</AddButton>
</FormWrapper>
</Formik>
</Container>
)
}
The code below is using antd v3,for the antd v4 the form.create() is already not available, I read the documentation,it shows to replace the form.create() by useform.I tried to put it in the code(the second code) but still not working. Hhow can I use useForm in the code?
import React from 'react'
import {Form, Input} from 'antd'
const EditableContext = React.createContext();
const EditableRow = ({ form, index, ...props }) => (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
);
export const EditableFormRow = Form.create()(EditableRow);
export class EditableCell extends React.Component {
state = {
editing: false,
};
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
if (editing) {
this.input.focus();
}
});
};
save = e => {
const { record, handleSave } = this.props;
this.form.validateFields((error, values) => {
if (error && error[e.currentTarget.id]) {
return;
}
this.toggleEdit();
handleSave({ ...record, ...values });
});
};
}
The useForm code
export const EditableFormRow = () => {
const { form, index, ...props } = useForm();
return (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
)
};
useForm() return array, you can get form like this:
import React from "react";
import ReactDOM from "react-dom";
import { Form, Input, Button } from "antd";
const App = () => {
return <>{["a#x.com", "b#x.com"].map((email) => EditRow({ email }))}</>;
};
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 }
};
const tailLayout = {
wrapperCol: { offset: 8, span: 16 }
};
const EditRow = ({ email }) => {
const [form] = Form.useForm();
const onFinish = (values) => {
console.log(values);
};
const onClick = () => {
console.log(form.getFieldValue("email"));
};
return (
<Form form={form} layout={layout} onFinish={onFinish}>
<Form.Item
name="email"
label="email"
rules={[{ required: true }]}
initialValue={email}
>
<Input />
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button onClick={onClick}>getFieldValue</Button>
</Form.Item>
</Form>
);
};
I need to fix a memory leak in my app but Im not sure how to. I have a component that uses a modal and I get the error when I am adding an item. The modal is reusable and I use it in other components as well. This is the main component:
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Card, Select, Form, Button } from 'antd';
import Table from 'components/Table';
import Modal from '../Modal';
import styles from '../index.module.scss';
const { Item } = Form;
const { Option } = Select;
const PersonForm = ({ details, form }) => {
const [modalVisible, setModalVisible] = useState(false);
const [name, setName] = useState(
details?.name ? [...details?.name] : []
);
useEffect(() => {
form.setFieldsValue({
name: name || [],
});
}, [form, details, name]);
const addName = values => {
setName([...name, values]);
setModalVisible(false);
};
const removeName = obj => {
setName([...name.filter(i => i !== obj)]);
};
const cancelModal = () => {
setModalVisible(false);
};
return (
<div>
<Card
title="Names
extra={
<Button type="solid" onClick={() => setModalVisible(true)}>
Add Name
</Button>
}
>
<Table
tableData={name}
dataIndex="name"
removeName={removeName}
/>
</Card>
<Item name="name">
<Modal
title="Add Name"
fieldName="name"
onSubmit={addName}
visible={modalVisible}
closeModal={cancelModal}
/>
</Item>
</div>
);
};
PersonForm.propTypes = {
details: PropTypes.instanceOf(Object),
form: PropTypes.instanceOf(Object),
};
PersonForm.defaultProps = {
form: null,
details: {},
};
export default PersonForm;
And this is the modal component:
import React from 'react';
import PropTypes from 'prop-types';
import { Input, Form } from 'antd';
import Modal from 'components/Modal';
import LocaleItem from 'components/LocaleItem';
const { Item } = Form;
const FormModal = ({ visible, closeModal, onSubmit, fieldName, title }) => {
const [form] = Form.useForm();
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 15 },
};
const addItem = () => {
form
.validateFields()
.then(values => {
onSubmit(values, fieldName);
form.resetFields();
closeModal(fieldName);
})
.catch(() => {});
};
const canceledModal = () => {
form.resetFields();
closeModal(fieldName);
};
return (
<Modal
onSuccess={addItem}
onCancel={canceledModal}
visible={visible}
title={title}
content={
<Form {...layout} form={form}>
<Item
name="dupleName"
label="Name:"
rules={[
{
required: true,
message: 'Name field cannot be empty',
},
]}
>
<Input placeholder="Enter a name" />
</Item>
</Form>
}
/>
);
};
FormModal.propTypes = {
visible: PropTypes.bool.isRequired,
closeModal: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
fieldName: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
};
FormModal.defaultProps = {};
export default FormModal;
I get a memory leak when I am in the test file when adding items in the modal. Can someone point out why this is happening and how to fix this? Thanks
Remove closeModal and form.resetFields from addItem function.
const addItem = () => {
form
.validateFields()
.then(values => {
onSubmit(values, fieldName); // when this onSubmit resolves it closes the modal, therefor these two lines below will be executed when component is unmounted, causing the memory leak warning
form.resetFields();
closeModal(fieldName);
})
.catch(() => {});
};
// instead maybe just:
const [form] = Form.useForm();
<Modal onOk={form.submit}>
<Form form={form}>
<Form.Item name="foo" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Modal>
Also, as far as I know you don't need to call form.validateFields as Ant Design's Form would do that automatically if rules are set in the Form.Item's.
As, I am new to react I don't know how to perform dynamic add and edit and cancel operations on the textarea. I have dynamic array , i want to perform edit and cancel operations for every textarea individually . If I click on a edit button the mouse cursor should point to the specific textbox, and it should turn into editable mode . If, I click on cancel button the specific textarea should turn into non-editable mode. codesandboxdemo please Run the code in codesandox and give me the solution
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: false
};
this.newText = {};
this.handleEdit = this.selectText.bind(this);
}
handleCancel(e,index) {
this.setState({disabled:true})
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
selectText(e, index) {
newText = this.state.count[index];
console.log(newText);
this.newText.select();
}
add(e) {
this.setState({ count: [...this.state.count, ""] ,disabled:false});
}
handleChange(e, index) {
this.state.count[index] = e.target.value;
this.setState({ count: this.state.count });
}
render() {
return (
<div>
<label>Enter the text</label>
{this.state.count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => (this.newText = newText)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled = {(this.state.disabled)? "disabled" : ""}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick = {(e) =>this.handleCancel(e,index)}> cancel </button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;
.App {
font-family: sans-serif;
text-align: center;
}
`]2
I just tried doing it this way for you. This is not a complete answer (just to make sure I don't spoon-feed you, but this is a possible approach). Tell me if this works?
import React, { useState } from "react";
import "./styles.css";
const App = () => {
const [Value, setValue] = useState("");
const [EditMode, setEditMode] = useState(false);
const toggleEditMode = () => setEditMode(!EditMode);
return EditMode ? (
<input
type="text"
value={Value}
onChange={(e) => setValue(e.target.value)}
onBlur={toggleEditMode}
/>
) : (
<span onClick={toggleEditMode}>{Value}</span>
);
};
export default App;
Click and it will make it editable. Come out and it shows updated value.
CodeSandbox: https://c4fog.csb.app/
Here is full working code of App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: [],
};
this.references = []
}
handleRef(r, index) {
this.references[index] = r
}
handleCancel(e,index) {
const { disabled } = this.state;
disabled[index] = true
this.setState({ disabled })
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
handleEdit(e, index) {
const { disabled } = this.state;
disabled[index] = false
this.setState({ disabled }, () => {
this.references[index].focus()
})
}
add(e) {
this.setState({ count: [...this.state.count, ""] });
}
handleChange(e, index) {
const { count } = this.state;
count[index] = e.target.value;
this.setState({ count });
}
render() {
const { disabled, count } = this.state
return (
<div>
<label>Enter the text</label>
{count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => this.handleRef(newText, index)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled ={disabled[index]}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick={(e) =>this.handleCancel(e,index)}>Cancel</button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;
Problem
It's not showing the elements within the item. It doesn't render anything at the moment.
List.js
import React from 'react';
const List = props => (
<div>
{
props.items.map((item, index) => {
return <div key={index}>
<h1>{item.name}</h1>
<p>{item.term}</p>
</div>
})}
</div>
);
export default List;
App.js
import React, {Component} from 'react'
import './App.css'
import List from './List';
class App extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
name: '',
items: []
};
}
onChange = (event) => {
const { name, value } = event.target;
this.setState({ [name]: value });
}
onSubmit = (event) => {
event.preventDefault();
this.setState({
term: '',
name: '',
items: [
...this.state.items,
this.state.term,
this.state.name
]
});
}
render() {
const { term, name, items } = this.state;
return (
<div>
<form className="App" onSubmit={this.onSubmit}>
<input name="term" value={this.state.term} onChange={this.onChange}/>
<input name="name" value={this.state.name} onChange={this.onChange}/>
<button>Submit</button>
</form>
<List items={this.state.items} />
</div>
);
}
}
Issue was in onSubmit, you need to convert to object and than add
onSubmit = event => {
event.preventDefault();
this.setState({
term: "",
name: "",
items: [...this.state.items, { term: this.state.term, name: this.state.name}]
});
setTimeout(() => { console.log(this.state.items) }, 0)
};
https://codesandbox.io/s/p7p128w7mx