OnClick related function from react component doesn't work - javascript

I am trying to pass a state to a component so i can update it's state whenever i type in a component's text field. However this is not working i am not sure why. Most of the examples I've found online were dealing with the similar problems on the same class. However i need to juggle this state between components.
Not only the state doesn't change but if i add the "value={information}" part in the textfield it doesn't let me type.
Here is an example of the code.
Class that uses the component:
class SomeClass extends Component {
state = {
information: '',
};
handleInfoChange(event) {
this.setState({
information: event.target.value,
});
}
render(){
return(
<div>
<TesteComponent
information={this.state.information}
handleInfoChange={this.handleInfoChange}
/>
Component code:
const TesteComponent = ({information}, handleInfoChange) => (
<Dialog
disableEscapeKeyDown
disableBackdropClick
>
<DialogContent>
<DialogContentText>
<p>Emails:</p>
<TextField value={information} className="bootstrapInput" onChange={() => handleInfoChange}/>
</DialogContentText>
</DialogContent>
</Dialog>
PS: I posted solely the part that is giving me trouble since the component in it's entirety works for the exception of the Onchange method problem i am having.
PS2: I forgot to add handleInfoChange being passed to the component in the question. It ahs been updated now.

TesteComponent doesn't have access to handleInfoChange. You can pass that function as a property like this
<TesteComponent
information={this.state.information}
handleInfoChange={this.handleInfoChange}
/>
and then in TesteComponent change it to
const TesteComponent = (props) => (
<Dialog
disableEscapeKeyDown
disableBackdropClick
>
<DialogContent>
<DialogContentText>
<p>Emails:</p>
<TextField value={props.information} className="bootstrapInput" onChange={() => props.handleInfoChange}/>
</DialogContentText>
</DialogContent>
</Dialog>

Firstly, you are not passing handleInfoChange function to TesteComponent as props
Secondly, you can not destructure and use arguments without destructuring together. You should instead write const TesteComponent = ({information, handleInfoChange}) => ( after passing the handleInfoChange as props
const TesteComponent = ({ information , handleInfoChange }) => (
<Dialog
disableEscapeKeyDown
disableBackdropClick
>
<DialogContent>
<DialogContentText>
<p>Emails:</p>
<TextField value={information} className="bootstrapInput" onChange={() => handleInfoChange}/>
</DialogContentText>
</DialogContent>
</Dialog>
SomeClass
class SomeClass extends Component {
state = {
information: '',
};
handleInfoChange(event) {
this.setState({
information: event.target.value,
});
}
render(){
return(
<div>
<TesteComponent
information={this.state.information}
handleInfoChange={this.handleInfoChange}
/>
)
}
}

class SomeClass extends Component {
state = {
information: ''
};
// changed to arrow function to bind 'this'
handleInfoChange = event => {
this.setState({information: event.target.value});
}
render() {
return(
<div>
<TesteComponent
information={this.state.information}
// pass handleInfoChange as a prop
handleInfoChange={this.handleInfoChange}
/>
</div>
);
}
}
const TesteComponent = ({information, handleInfoChange}) => (
<Dialog disableEscapeKeyDown disableBackdropClick>
<DialogContent>
<DialogContentText>
<p>Emails:</p>
<TextField
className="bootstrapInput"
value={information}
onChange={handleInfoChange}
/>
</DialogContentText>
</DialogContent>
</Dialog>
);

first of all you should bind your click event and set in state and here i am going to print change value in console ....
here is my code try this one....
class SomeClass extends Component {
state = {
information: '',
};
this.handleInfoChange= this.handleInfoChange.bind(this);
handleSubmit = event => {
event.preventDefault();
}
handleInfoChange(event) {
this.setState({
information: event.target.value,
console.log(this.state.information);
});
}
render(){
return(
<div>
const TesteComponent = ({information}, handleInfoChange) => (
<Dialog
disableEscapeKeyDown
disableBackdropClick
>
<form onSubmit={this.handleSubmit}>
<DialogContent>
<DialogContentText>
<p>Emails:</p>
<TextField value={information} className="bootstrapInput" onChange={this.handleInfoChange}/>
</DialogContentText>
</DialogContent>
</Dialog></div></form>

Related

Dialog of material UI has afterimage when being closed

Introduction
Bascially <Dialog /> receives open and onClose as props. open is boolean from state and onClose is a function that changes the state.
I made <CustomModal /> that wraps <Dialog />, which receives another prop content that defines what to display on <Dialog />.
// CustomModal.jsx
const CustomModal = props => (
<Dialog {...props} sx={{ '& .MuiDialog-paper': { padding: '2em' } }}>
{props.content}
</Dialog>
);
And I'm delivering handlers using context so that my modal could be open and closed everywhere.
// modalHandlersContext.js
const initialState = {
open: false,
content: null,
};
const ModalHandlersProvider = ({ children }) => {
const [modal, setModal] = useState(initialState);
const handlers = {
openModal: payload => setModal({ open: true, ...payload }),
closeModal: () => setModal(initialState),
};
return (
<ModalHandlersContext.Provider value={handlers}>
{children}
<CustomModal
open={modal.open}
onClose={handlers.closeModal}
content={modal.content}
></CustomModal>
</ModalHandlersContext.Provider>
);
};
When I want to open modal somewhere, I execute a function like this
const onLogin = () =>
openModal({
content: <h1>component</h1>,
});
That is, I pass a component. (I used h1 for a simple example)
Main subject
But when I close it, it's not clean.
I experimented on this to check when this happens.
It happens
With css, display something from props(same code as above)
const CustomModal = props => (
<Dialog {...props} sx={{ '& .MuiDialog-paper': { padding: '2em' } }}>
{props.content}
</Dialog>
);
It doesn't happen
Without css, display something from props
const CustomModal = props => (
<Dialog {...props}>
{props.content}
</Dialog>
);
2,3. With/Without css, display just plain text
const CustomModal = props => (
<Dialog {...props} sx={{ '& .MuiDialog-paper': { padding: '2em' } }}>
content
</Dialog>
);
const CustomModal = props => (
<Dialog {...props}>
content
</Dialog>
);
So after that, I tried using <DialogContent /> instead of css but It didn't work. But I have tried using <Modal /> instead of <Dialog /> and it hasn't caused any problems.
I wanna use <Dialog /> if possible but now can't find the cause.
Can anyone help?

Why is my page reloading after onChange trigger update?

I have added different forms in different methods but when I type anything in input fields, the page reloads keeping the states and again I have to click on the field and type and same cycle happens. It is working fine if I add everything in return. Can somebody tell explain why is this happening and how to stop it?
I am also sharing a piece of code.
function MyForm() {
const [commentForm, setCommentForm] = useState({
Comment: "",
});
const onCommentChange = (obj) => {
setCommentForm((prevState) => {
return {
...prevState,
...obj,
};
});
};
const IForm = () => (
<Table>
<CardBody>
<Row>
<Col className="col-2">
<Label>Comment: </Label>
</Col>
<Col className="col-1">
<Input type="text"
value={commentForm.Comment}
onChange={(e) =>
onCommentChange({ Comment: e.target.value })} />
</Col>
</Row>
</CardBody>
</Table>
);
return (
<div>
<IForm />
</div>
)
}
export default MyForm
that's because you define IForm as A component inside the current component which is not correct. so you have two solutions.
1 - move IFORM Component outside the current react.
function MyForm() {
const [commentForm, setCommentForm] = React.useState({
Comment: ""
});
const onCommentChange = (obj) => {
setCommentForm((prevState) => {
return {
...prevState,
...obj
};
});
};
return (
<div>
<IForm commentForm={commentForm} onCommentChange={onCommentChange} />
</div>
);
}
export default MyForm;
const IForm = ({ commentForm, onCommentChange }) => (
<Table>
<CardBody>
<Row>
<Col className="col-2">
<Label>Comment: </Label>
</Col>
<Col className="col-1">
<Input type="text"
value={commentForm.Comment}
onChange={(e) =>
onCommentChange({ Comment: e.target.value })} />
</Col>
</Row>
</CardBody>
</Table>
);
2 - declare the IForm as a normal function inside the current component.
function MyForm() {
const [commentForm, setCommentForm] = React.useState({
Comment: ""
});
const onCommentChange = (obj) => {
setCommentForm((prevState) => {
return {
...prevState,
...obj
};
});
};
const form = () => (
<Table>
<CardBody>
<Row>
<Col className="col-2">
<Label>Comment: </Label>
</Col>
<Col className="col-1">
<Input type="text"
value={commentForm.Comment}
onChange={(e) =>
onCommentChange({ Comment: e.target.value })} />
</Col>
</Row>
</CardBody>
</Table>
);
return <div> {form()} </div>;
}
export default MyForm;
The reason is that the IForm component is declared inside the MyForm Component. Which means that whenever the state of MyForm Component changes it will refresh its dom tree. And when the dom will rerender the functional component IForm will be executed again that's why you'll always lose the focus of the input but you never lose the state of the MyForm component.
To stop it from being happening either declare the IForm Component outside of the MyForm component or move the jsx of the IForm inside the Return of MyFOrm component.
You should just setCommentForm the value. I don't think you need to spread the prevState.
What you want to achieve is to set the state value to the new one.
Also, you don't have any useEffect right?

Modal is not Closing ReactJS Hooks Using Parent and Child Components

I am opening Model (child Component) on Button Click from Parent Component, it opens very well but its not closing and it shows some error:
Uncaught TypeError: setOpen is not a function from Child Component
Here is My Parent Component
<TableCell>
<Button
variant="contained"
size="small"
color="primary"
onClick={() => deleteHandler(index)}
>
Delete Me
</Button>
</TableCell>
{console.log(open)}
{open && <AddList open={open} setOpen={open} />}
My Child Component
export default function TransitionsModal(open, setOpen) {
const classes = useStyles();
// const [openL, setOpenL] = React.useState(null);
// const handleOpen = () => {
// setOpen(true);
// };
const handleClose = () => {
setOpen(!open);
};
return (
<div>
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500
}}
>
<Fade in={open}>
<div className={classes.paper}>
<h2 id="transition-modal-title">Transition modal</h2>
<p id="transition-modal-description">
react-transition-group animates me.
</p>
</div>
</Fade>
</Modal>
</div>
);
}
Your first issue is that you are passing a Boolean for the setOpen prop rather than the setOpen function itself, so change it to setOpen={setOpen}.
// RenderList.js
const RenderList = props => {
// ...
return (
...
{open && <AddList open={open} setOpen={setOpen} />}
)
}
Your second issue is that you're not destructing props properly in the TransitionsModal component. Use {} to destruct the props object and grab what you need.
// AddList.js
export default function TransitionsModal({ open, setOpen }) {
// ...
}
Here's the fixed example:
CodeSandbox
Hope this helps.
Hi take a look at this
https://codesandbox.io/s/frosty-bird-5yh5g
in RenderList.js you didn't pass setOpen
{open && <AddList open={open} setOpen={setOpen} />}
also export default function TransitionsModal({ open, setOpen }) {

Props not recognized

When clicking a button i have an event error, the problem is i dont know how to convert this with hooks
const Header = () => {
const [value, setValue] = React.useState(0);
function handleChange(event, newValue) {
setValue(newValue);
}
function onLogoutClick(e) {
e.preventDefault();
this.props.logoutUser();
}
//this.onLogoutClick = this.onLogoutClick.bind(this);
return (
<div className={classes.root}>
<AppBar position="sticky">
<Tabs value={value} onChange={handleChange} centered>
{" "}
{/* <Tabs value={value} onChange={handleChange}>
{sections.map(section => (
<Tab label={section} />
))}
</Tabs> */}{" "}
<Tab label="Indicadores Globais" />
<Tab label="Indicadores Colaboradores" />
<Tab label="Indicadores Produto" />
<Tab label="Indicadores Temporais" />
<Button
color="inherit"
className={classes.classesButton}
onClick={onLogoutClick}
>
Logout
</Button>
TypeError: Cannot read property 'props' of undefined when clicking on the button. I know the problem is on the onClick={onLogoutClick} but im not sure how to solve this. Any help?
An event handler will override this in the callback with the event object. To make sure the component is scoped in the callback, you need to bind it to the function.
<Button
color="inherit"
className={classes.classesButton}
onClick={onLogoutClick.bind(this)}
>
this inside onLogoutClick points to the html element. If you want to access the component as this, You need to bind the action with this.
<Button
color="inherit"
className={classes.classesButton}
onClick={onLogoutClick.bind(this)}
>
But this is not the recommended method as it binds this with action every time component renders. The recommended method is to bind the action with this in the constructor.
constructor(props) {
super(props);
this.state = {
};
this.onLogoutClick = this.onLogoutClick.bind(this);
}

React - TypeError: _this.setState is not a function

I am playing with React and trying to save the text that user type to the input to the state. I have added to the textarea an onChange attribute for setting the state.
However, when I start typing, I see error in the console stating TypeError: _this.setState is not a function.
I've tried different ways of trying to fix it, but still don't have it.
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={e => this.setState({ item_msg: e.target.value })} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
class App extends Component {
constructor () {
super();
this.state = {
item_msg: ''
}
}
handleSubmit(e){
e.preventDefault();
console.log(this.state.item_msg);
}
render() {
return (
<div className="App">
<MainHeaderr />
<Container>
<NewItemForm send_form={this.handleSubmit.bind(this)} />
</Container>
</div>
);
}
}
export default App;
Functional components do not have lifecycle methods and... state :)
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={e => this.setState({ item_msg: e.target.value })} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
This won't work:
onChange={e => this.setState({ item_msg: e.target.value })} />
What you need is to pass callback:
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={props.onInputChange} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
class App extends Component {
constructor () {
super();
this.state = {
item_msg: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(e){
e.preventDefault();
console.log(this.state.item_msg);
}
handleInputChange(e) {
this.setState({ item_msg: e.target.value })
}
render() {
return (
<div className="App">
<MainHeaderr />
<Container>
<NewItemForm send_form={this.handleSubmit} onInputChange={this.handleInputChange} />
</Container>
</div>
);
}
}
I get where you are coming from, but NewItemForm will get transpiled to React Element so this will reference that Element, not the App component.
React without JSX
Functional components are stateless so you can't call setState within them. You can pass a callback from your parent component that sets state in the parent component as follows:
handleChange = e => this.setState({ item_msg: e.target.value });
<NewItemForm onChange={this.handleChange} />
And then in your NewItemForm component:
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={props.onChange}
/>
NewItemForm is function component and function comopent does not have lifecycle method use class component.
You need to either use arrow function or bind the function in constructor like below
constructor(props) {
super(props);
this.state = { date: new Date() };
this.tick = this.tick.bind(this);
}
setInterval(()=>this.tick, 1000);
or Use arrow function
setInterval(()=>this.setState({
date: new Date(),
}), 1000);

Categories

Resources