I render a form and a list. It works just fine at the initial load up:
<UsersList
users={this.state.users}
/>
<SendMessageForm
sendMessage={this.addMessage}
/>
However, when the SendMessageForm is submitted this.state.users loses its value and I get the error of Cannot read property 'map' of undefined.
Here is the SendMessageForm:
export default class SendMessageForm extends React.Component {
constructor() {
super();
this.state = {
message: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
message: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
this.props.sendMessage(this.state.message);
this.setState({
message: ''
});
}
render() {
return (
<div id="MessageField">
<form
onSubmit={this.handleSubmit}
className="send-message-form">
<input
onChange={this.handleChange}
value={this.state.message}
placeholder="Type your message and hit ENTER"
type="text"
/>
</form>
</div>
);
}
}
Here is the UserList:
import React, { Component } from 'react';
class UsersList extends Component {
render() {
return (
<div id="UList">
<ul className="users-list">
{this.props.users.map((user, index) => {
return (
<li key={index}>
<span>{user}</span>
</li>
);
})}
</ul>
</div>
);
}
}
export default UsersList;
Could you help me understand how the state variable users loses its value?
EDIT:
Adds message to the MessageList. MessageList works just fine, the problem is with the UsersList. By the way I am using Chatkit library.
addMessage(text) {
this.state.currentUser.sendMessage({
text,
roomId: this.state.roomId.toString()
})
.catch(error => console.error('error', error));
}
Related
I have a problem I can not solve myself in relation to react.
What I am trying to do is add props to my Component
So I can use my compnent again and again just with a string relative to a variable so I can just write e.g.
I really searched for some different things but none that worked.
Just hoping you can get me on.
Hope it makes sense otherwise feel free to ask
My Component
import React, { Component } from "react";
export default class UserSelections extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
DataisLoaded: false,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
// ComponentDidMount is used to
// execute the code
componentDidMount() {
fetch(
"URL")
.then((res) => res.json())
.then((json) => {
this.setState({
items: json,
DataisLoaded: true
});
})
}
render() {
const { DataisLoaded, items } = this.state;
if (!DataisLoaded) return <div>
<h1> Vent et øjeblik... </h1> </div> ;
return (
<div className = "App">
<h1> Fetch data from an api in react </h1>
<form onSubmit={this.handleSubmit}>
<label><select name={this.state.slug} value={this.state.value} onChange={this.handleChange}>
{ --->Need Variable here<--- Down here
items.filter(slug => slug.slug === **'bygnings-st'**).map((item, index) => (
<option value={ item.outputvalue } key={index}>{ item.outputvalue }</option>
))
}</select>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
import React from "react";
import UserSelections from "./components/UserSelections";
import './App.css';
function App() {
return (
<div className="App">
<UserSelections **Need props here** /> <-------------------
</div>
);
}
export default App;
Best regards
Morten
If you want to pass a string as prop:
const value = "hi";
<UserSelections stringProp={value} />
And you display the value with:
{this.props.stringProp}
inside of the UserSelections component
I'm having a hard time making this form submit twice. What do I mean? When I click on submit, the form (on General.js) is hidden and it renders another component (DisplayGeneral.js) displaying the user's input. Then I added a button to bring back the form so the user can edit the information, the problem is that it doesn't toggle again when I click on the form button, you know? What am I missing here? Please, I appreciate any help.
General.js
import React, { Component } from 'react';
import '../style/style.css';
import DisplayGeneral from './DisplayGeneral';
class General extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
showing: true,
isEditing: true,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value,
});
}
handleSubmit(e) {
e.preventDefault();
const { showing } = this.state;
this.setState({
showing: !showing,
});
}
handleClick(e) {
e.preventDefault();
const { isEditing } = this.state;
this.setState({
isEditing: !isEditing,
});
}
form = () => {
return (
<div>
<form className='generalForm'>
<label htmlFor='nameInput' className='row'>
Name:{' '}
<input
type='text'
name='name'
value={this.state.name}
onChange={this.handleChange}
id='nameInput'
/>
</label>
<button onClick={this.handleSubmit}>Submit</button>
</form>
</div>
);
};
renderGeneral() {
const {
isEditing,
name,
} = this.state;
return (
<div>
{isEditing ? (
<div>
<DisplayGeneral
handleSubmit={this.handleSubmit}
name={name}
/>
<button onClick={this.handleClick}>Edit</button> // button added
</div>
) : (
this.form()
)}
</div>
);
}
render() {
const { showing } = this.state;
return (
<section className='divGeneral'>
<div className='sectionTitle'>
<h1>General Information</h1>
</div>
{showing ? this.form() : this.renderGeneral()}
</section>
);
}
}
export default General;
DisplayGeneral.js
import React, { Component } from 'react';
class DisplayGeneral extends Component {
render() {
const { name } = this.props;
return (
<section className='renderedSection'>
<article>
<span className='spanArtc'>Name: </span>
{name}
</article>
</section>
);
}
}
export default DisplayGeneral;
If you just want to toggle the form you can keep only one flag isEditing and change it to true, if you want to show the form and false for showing information.
import React, { Component } from 'react';
import '../style/style.css';
import DisplayGeneral from './DisplayGeneral';
class General extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
isEditing: true,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value,
});
}
handleSubmit(e) {
e.preventDefault();
this.setState({
isEditing: false,
});
}
handleClick(e) {
e.preventDefault();
this.setState({
isEditing: true,
});
}
form = () => {
return (
<div>
<form className='generalForm'>
<label htmlFor='nameInput' className='row'>
Name:{' '}
<input
type='text'
name='name'
value={this.state.name}
onChange={this.handleChange}
id='nameInput'
/>
</label>
<button onClick={this.handleSubmit}>Submit</button>
</form>
</div>
);
};
renderGeneral() {
const { name } = this.state;
return (
<div>
<DisplayGeneral handleSubmit={this.handleSubmit} name={name} />
<button onClick={this.handleClick}>Edit</button> // button added
</div>
);
}
render() {
const { isEditing } = this.state;
return (
<section className='divGeneral'>
<div className='sectionTitle'>
<h1>General Information</h1>
</div>
{isEditing ? this.form() : this.renderGeneral()}
</section>
);
}
}
export default General;
I'm currently working on a project that uses QuillJS for a rich text editor. I need to post the rich text content to my backend but I'm not sure how to access the QuillJS output.
In RichTextEditor.js
import React, { Component } from "react";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
class RichTextEditor extends Component {
constructor(props) {
super(props);
// this.formats = formats;
this.state = { text: "" }; // You can also pass a Quill Delta here
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ text: value });
const text = this.state;
console.log(text);
}
render() {
return (
<ReactQuill
value={this.state.text}
onChange={this.handleChange}
formats={this.formats}
modules={this.modules}
/>
);
}
}
export default RichTextEditor;
The console.log(text) basically just outputs the content of the rich text editor. Something like this "<p><em>aasdasdasd</em><strong><em>asdasdasdasd</em></strong></p>"
In Post.js
import React, { Component } from "react";
import RichTextEditor from "./RichTextEditor.js";
import "../../css/Post.css";
class Post extends Component {
constructor(props) {
super(props);
this.state = {
question: "",
};
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
console.log(this.state);
};
handleSubmit = (e) => {
e.preventDefault();
const { question } = this.state;
console.log("Question");
console.log(question);
render() {
const { question } = this.state;
return (
<div className="post">
<div className="post__container">
<form onSubmit={this.handleSubmit}>
<div className="post__richTextEditor">
<RichTextEditor value={question} onChange={this.onChange} name="question" />
</div>
</form>
</div>
</div>
);
}
}
export default Post;
I'm trying to update the state of the question but it doesn't seem to be updating. console.log(question) only outputs a single string.
How can I access the same string output from RichTextEditor.js?
Your RichTextEditor component should not handle change, it should only receive props from higher component:
class RichTextEditor extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactQuill
value={this.props.value}
onChange={this.props.onChange}
formats={this.formats}
modules={this.modules}
/>
);
}
}
export default RichTextEditor;
Then your Post component pass value and onChange props to RichTextEditor:
class Post extends Component {
constructor(props) {
super(props);
this.state = {
question: "",
};
this.onChange = this.onChange.bind(this);
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
console.log(this.state);
};
handleSubmit = (e) => {
e.preventDefault();
const { question } = this.state;
console.log("Question");
console.log(question);
render() {
const { question } = this.state;
return (
<div className="post">
<div className="post__container">
<form onSubmit={this.handleSubmit}>
<div className="post__richTextEditor">
<RichTextEditor value={question} onChange={this.onChange} name="question" />
</div>
</form>
</div>
</div>
);
}
}
in RichTextEditor.js
handleChange(value) {
this.setState({ text: value });
const text = this.state;
console.log(text);
props.onChange(text); // passing the inner State to parent as argument to onChange handler
}
Now in Post.js
onChange = (newStateString) => {
//this.setState({ [e.target.name]: e.target.value });
console.log(newStateString); // you should get the string here
};
Here is my simple to-do app program where I have made only one component which takes in the input form user and passes that input value to App.js to update items in App.js state.
todo-form.component.js
import React from 'react';
class SignInForm extends React.Component {
constructor(){
super();
this.state ={
temp: null
};
}
handleChange = (e) => {
e.preventDefault();
this.setState({
temp: e.target.value
},
console.log(this.state)
);
// this.props.addInput(e.target.value);
}
handleSubmit= (e) => {
e.preventDefault();
console.log(this.state.temp);
this.props.addInput(this.state.temp);
}
render(){
return(
<div className="container-form">
<form onSubmit={this.handleSubmit}>
<input
name="description"
type="text"
placeholder="add description"
onChange={this.handleChange}
value={this.state.input}
/>
<button type="submit">ADD</button>
</form>
</div>
);
}
}
export default SignInForm;
App.js
import React from 'react';
import './App.css';
import SignInForm from './components/todo-form/todo-form.component'
import ItemList from './components/todo-list/todo-list.component';
class App extends React.Component {
constructor(){
super();
this.state = {
input: []
};
}
addInput = (item) => {
let newInput=[...this.state.input,item];
console.log(newInput);
this.setState = ({
input: newInput
},
console.log(this.state)
);
}
render(){
return (
<div className="App">
<h1>TO-DO LIST</h1>
<SignInForm addInput={this.addInput} />
</div>
);
}
}
export default App;
On taking input the state inside todo-form.component.js is getting updated with the typed input value but on passing state.temp in handleChange function, the state inside App.js is not updating when addInput function is called.
Please help me on this issue and how my state is not getting updated in App.js??
Your setState is the problem. Have a look at my code.
App.js
class App extends React.Component {
state = {
input: [],
};
addInput = (item) => {
let newInput = [...this.state.input, item];
//setState should be this way
this.setState({
input: newInput,
});
};
render() {
return (
<div className="App">
<h1>TO-DO LIST</h1>
{this.state.input.map((el) => (
<li> {el}</li>
))}
<SignInForm addInput={this.addInput} />
</div>
);
}
}
export default App;
Login file.
class SignInForm extends React.Component {
// constructor(props) {
// super(props);
state = {
temp: null,
};
// }
handleChange = (e) => {
e.preventDefault();
this.setState({
temp: e.target.value,
});
// this.props.addInput(e.target.value);
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.temp);
this.props.addInput(this.state.temp);
};
render() {
return (
<div className="container-form">
<form onSubmit={this.handleSubmit}>
<input
name="description"
type="text"
placeholder="add description"
onChange={this.handleChange}
value={this.state.input}
/>
<button type="submit">ADD</button>
</form>
</div>
);
}
}
export default SignInForm;
I have a simple form on child component A. On submit I'm passing the data from the form to the parent component and storing the data in state.. I want to then move this data to a different child, child component B.(the sibling of A)
I'm having trouble getting the data to be rendered on submit in component B. I'm not sure how to trigger the rendering on submit or how to pass this information via props on submit.
Here is the Parent
class Msg extends React.Component {
constructor(props) {
super(props);
this.storeInput = this.storeInput.bind(this);
this.state = {
name: '',
msg: ''
};
}
storeInput (d) {
this.setState({
name: d.name,
msg: d.msg
})
}
render() {
return(
<div className='msgContainer'>
<Input
passBack={this.storeInput}/>
<Output />
</div>
)
}
}
Here is Component A
class Input extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
name: '',
msg: ''
};
}
handleChange(e) {
this.setState({[e.target.name]: e.target.value})
}
handleSubmit(e) {
e.preventDefault();
this.props.passBack(this.state);
}
render () {
const name = this.state.name;
const msg = this.state.msg;
return (
<div className='form-container'>
<form action="">
<label htmlFor="">name</label>
<input
name='name'
value={name}
onChange={this.handleChange}
type='text'></input>
<label htmlFor="">message</label>
<textarea
name='msg'
value={msg}
onChange={this.handleChange}
rows='5' cols='80'></textarea>
<input
onClick={this.handleSubmit}
type='submit'></input>
</form>
</div>
)
}
}
Here is Component B
class Output extends React.Component {
render () {
return(
<div className='output'>
</div>
)
}
}
Simply pass the state as props to Output like so:
Parent Component:
import React from 'react';
import Input from './Input';
import Output from './Output';
class Msg extends React.Component {
state = { name: '', msg: '' };
storeInput = d => {
this.setState({ name: d.name, msg: d.msg });
};
render() {
// destructure the state
const { name, msg } = this.state;
return (
<div className="msgContainer">
<Input passBack={this.storeInput} />
{/* pass the state as props to Output */}
<Output name={name} msg={msg} />
</div>
);
}
}
export default Msg;
Input.js
import React from 'react';
class Input extends React.Component {
state = { name: '', msg: '' };
handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.passBack(this.state);
this.setState({ name: '', msg: '' }); // clear up the input after submit
};
render() {
const { name, msg } = this.state;
return (
<div className="form-container">
<form onSubmit={this.handleSubmit}>
<label htmlFor="">name</label>
<input
name="name"
value={name}
onChange={this.handleChange}
type="text"
/>
<label htmlFor="">message</label>
<textarea
name="msg"
value={msg}
onChange={this.handleChange}
rows="5"
cols="80"
/>
<input type="submit" />
</form>
</div>
);
}
}
export default Input;
Output.js
import React from 'react';
// destructure the props coming in from Msg
// no need for a class-based component
const Output = ({ name, msg }) => (
<div className="output">
<div>Output</div>
<p>{name}</p>
<p>{msg}</p>
</div>
);
export default Output;
Live demo: https://jsfiddle.net/c8th67zn/