React not re-rendering after state change - reactjs

import React, {Component, Fragment} from 'react'
import axios from 'axios'
import PropTypes from "prop-types";
import { connect } from 'react-redux'
import { postComment } from "../../../actions/comments"
import './styles.scss'
export class Comments extends Component {
constructor(props) {
super(props)
this.state = {
comment: "",
author: null
}
}
static propTypes = {
postComment: PropTypes.func.isRequired
};
componentDidMount() {
axios
.get(`/api/auth/user`)
.then(res => {
const author = res.data.id
this.setState({author});
})
.catch(err => console.log(err));
}
onSubmit(e) {
e.preventDefault();
const variables = {
content: this.state.comment,
post: this.props.post.id,
author: this.state.author
}
this.props.postComment(variables)
this.setState({content: ""});
}
onFieldChange(fieldName) {
return function (event) {
this.setState({[fieldName]: event.target.value});
}
}
render() {
return (
<Fragment>
<div class="input">
<form style={{ display:'flex'}} onSubmit={e => this.onSubmit(e)}>
<div class="input-group">
<input
class="form-control rounded-corner"
style={{width: '100%', borderRadius: '5px'}}
onChange={this.onFieldChange('comment').bind(this)}
value = {this.state.comment}
placeholder="Leave a comments"
/>
<span class="input-group-btn p-l-10">
<button class="btn btn-primary f-s-12 rounded-corner">Comment</button>
</span>
</div>
</form>
</div>
<div>
{/* Comment Lists */}...
))}
</div>
</Fragment>
);
}
}
export default connect(
null,
{ postComment }
)(Comments);
This is a page when I add comments to the posts, which works fine but it doesn't update immediately and I have to refresh. The componentDidMount method uses axios to get current user for setting the author for the current comment. I'm changing the state after the form submit, I can't see what the issue is.

Related

Binding and saving react button value

I am trying to save the value of the button as a string.If i click residence button it will save the value in categoryName as 'residence' or 'commercial' and redirect to another page .I have built a Rest API in the backend to bind and save the value in database.The code is something like this
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
class CustomizedButtons extends React.Component {
constructor(props) {
super(props);
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
category: " ",
};
}
saveValue = () => {
console.log('savecategory');
axios.post( this.state.apiUrl+'/api/v1/leadsurvey/category', {
'categoryName':this.state.category,
}, {})
};
render() {
const { classes} = this.props;
return (
<div>
<div>
<p>What is the type of your property?</p>
<div>
<button onClick={() => this.saveValue()}>Residence</button>
<button onClick={() => this.saveValue()}>Commercial</button>
</div>
<div style={{marginTop: '90px'}}>
</div>
</div>
</div>
);
}
}
export default CustomizedButtons;
I am not getting how to make it work to bind and save.In case of saving form value i did something like this.
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
FreeQuoteName :"",
};
this.handleFreeQuoteName = this.handleFreeQuoteName.bind(this);
saveFreeQuote = () => {
console.log('saveFreeQuote ...', this.state);
axios.post( this.state.apiUrl+'/api/v1/SalesLead/save', {
'name': this.state.FreeQuoteName,
}
}
handleFreeQuoteName(event) { this.setState({ FreeQuoteName: event.target.value }); }
<Form>
<p>Name*</p>
<input maxLength="30" onChange={this.handleFreeQuoteName} value={this.state.FreeQuoteName}
type="text" placeholder="Enter name here"/>
<div style={{textAlign:'center', marginTop:'35px', marginBottom:'22px'}} className={card.disable}>
<button disabled={isDisabled} type="button" fullwidth="true" variant="contained"
onClick={() => this.saveFreeQuote()} style={{padding: '9px 0px'}}>Submit</button>
</Form>
I want to do same for the value button.If i click the button it will save the value as a string and redirect to another page.How can i do it?
from your post I assumed that you want to save button value in state and also want to initiate the axios request while button click.
try to change like below
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import axios from 'axios';
class CustomizedButtons extends React.Component {
constructor(props) {
super(props);
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
category: "",
};
}
saveValue = (e) => {
console.log('savecategory', e.target.innerHTML);
this.setState({
category: e.target.innerHTML
}, this.makeAxiosRequest);
};
makeAxiosRequest = () => {
axios.post( this.state.apiUrl+'/api/v1/leadsurvey/category', {
'categoryName':this.state.category,
}, {})
};
render() {
const { classes} = this.props;
return (
<div>
<div>
<p>What is the type of your property?</p>
<div>
<button onClick={this.saveValue}>Residence</button>
<button onClick={this.saveValue}>Commercial</button>
</div>
<div style={{marginTop: '90px'}}>
</div>
</div>
</div>
);
}
}
export default CustomizedButtons;
here am using callback function inside setState() to initiate axios request after button value saved in state.
Hope this helps.

How to clear input after form submission in react?

I want to clear input after my form submission get successful. I don't want to use reset button in this case.
I have passed submitted data to api that is in another file.
Please help.
file forgotPassword.js
import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { forgotPassword } from "../../actions/authActions";
import classnames from "classnames";
class ForgotPassword extends Component {
constructor() {
super();
this.state = {
email:"",
errors: {}
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
onChange = e => {
this.setState({ [e.target.id]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
var emailId = {
email: this.state.email
};
this.props.forgotPassword(emailId, this.props.history);
};
render(){
const { errors } = this.state;
return (
<div className="container">
<div className="row">
<div className="col s8 offset-s2">
<div className="col s12" style={{ paddingLeft: "11.250px" }}>
<h4><b>Forgot Password</b></h4>
</div>
<form noValidate onSubmit={this.onSubmit}>
<div className="input-field col s12">
<input
onChange={this.onChange}
value={this.state.email}
error={errors.email}
id="email"
type="email"
className={classnames("", {
invalid: errors.email
})}
/>
<label htmlFor="email">Email</label>
<span className="red-text">{errors.email}</span>
</div>
<div className="col s12" style={{ paddingLeft: "11.250px" }}>
<button
style={{
width: "150px",
borderRadius: "3px",
letterSpacing: "1.5px",
marginTop: "1rem"
}}
type="submit"
className="btn btn-large waves-effect waves-light hoverable blue accent-3"
>
Submit
</button>
</div>
</form>
</div>
</div>
</div>
);
}
onHandleSubmit(e) {
e.preventDefault();
const email = this.state.email;
this.props.onSearchTermChange(email);
console.log(email);
this.setState({
email: ''
});
}
}
ForgotPassword.propTypes = {
forgotPassword: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
});
export default connect(
mapStateToProps,
{ forgotPassword }
)(ForgotPassword);
File authaction.js where calling api
import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";
import { GET_ERRORS, SET_CURRENT_USER, USER_LOADING} from "./types";
export const forgotPassword = (userData, history) => dispatch => {
axios
.post("/api/users/forgotpassword", userData)
.then(res =>
console.log("forgot password",res)
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
After successfull result on api I'm unable to clear input in forgot password form component.
Please let me know if any other way to do this task.I'm a newbie in react.
Many thanks for help.
Changing the value of a TextInput component
You can change the context of the input after an onPress event coming from a button.
export default class App extends React.Component {
state = {
text : "Username"
}
render() {
return (
<View style={styles.container}>
// TextInput gets its value from the state.text above.
<TextInput value={this.state.text } style={{borderColor:"black", border:1}}/>
// Button calls the function in onPress when it is pressed, which cleans up the state.text
<Button title="CLEAN" onPress={() => this.setState({text: ""})} />
</View>
);
}
}

not able to share state between two components in react

I have two components-AskQuestion and SingleQuestion
I want to pass the data from AskQuestion to SingleQuestion. How to make this.state.form content available in SingleQuestion component.
AskQuestion.jsx
import React, { Component } from 'react';
import EditableTagGroup from '../EditableTagGroupComponent/EditableTagGroup';
import { createHashHistory } from 'history'
const history = createHashHistory();
class AskQuestion extends Component {
constructor(props) {
super(props)
this.state = {
form: {
Title: '',
Content: '',
Tags: sessionStorage.getItem("TG"),
}
};
this.onChange = this.onChange.bind(this);
this.changeHandler = this.changeHandler.bind(this);
this.submitHandler = this.submitHandler.bind(this);
}
changeHandler(e) {
e.persist();
let store = this.state;
store.form[e.target.name] = e.target.value;
this.setState(store);
}
submitHandler(e) {
e.preventDefault();
fetch('cons/ques/create', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(
{
"Request": {
"RequestInfo": {
"userId": "2"
},
"RequestPayload": {
"Questions": [
{
"questionId": 0,
"questionTitle": this.state.form.Title,
"isAnswered": false,
"questionContent": this.state.form.Content,
"tags": [{
"tagId": 1,
"tagName": "Java",
"tagUsage": 1
}]
}
]
}
}
}
)
}).then(res => {
console.log(res);
this.redirect();
return res;
}).catch(err => err);
}
redirect = () => {
this.props.history.push('/SingleQuestion');
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
const { form } = this.state;
return (
<div className="container">
<h2>ASK A QUESTION</h2>
<form onSubmit={this.submitHandler}>
<div className="form-group">
<label htmlFor="Title">Title:</label>
<input name="Title" type="text" className="form-control" id={this.state.form.Title} placeholder="Enter Title" onChange={this.changeHandler} />
</div>
<div className="form-group">
<label htmlFor="Content">Content:</label>
<textarea type="Content" className="form-control" id={this.state.form.Content} placeholder="Content" name="Content" style={{ height: "300px" }} onChange={this.changeHandler}></textarea>
</div>
<div className="form-group">
<label htmlFor="Tags">Tags:</label>
<EditableTagGroup />
</div>
<button type="submit" className="btn btn-default">Post Question</button>
<button type="submit" className="btn btn-default">Discard</button>
</form>
</div>
)
}
}
export default AskQuestion;
SingleQuestion.jsx
import React, { Component } from 'react';
import './SingleQuestion.css';
class SingleQuestion extends Component {
constructor(props) {
super(props)
this.state = {
};
}
render() {
return (
<div class="question-container col-lg-10">
<div class="question-icons pull-left">
<div class="rating">
<i class="button rating-up fa fa-thumbs-o-up" aria-hidden="true"></i>
<span class="counter">0</span>
<i class="button rating-down fa fa-thumbs-o-down" aria-hidden="true"></i>
</div>
</div>
<div class="result-link pull-left" style={{ paddingLeft: "30px", paddingTop: "55px" }}>
<h1>{this.props.Title}</h1>
</div>
</div>
)
}
}
export default SingleQuestion;
I saw posts like how to share state but didn't help me. mostly i saw something like this
<SingleQuestion callback=*****/>
if I do like that where ever I use this <SingleQuestion ------/> that component will be rendered which i don't want to do. I am new to reactjs please
help me in this..
Thanks in advance!!
This is an example to pass data between parallel components in reactjs
// App.js
import React, { Component } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import SingleQuestion from './SingleQuestion';
import AskQuestion from './AskQuestion';
class App extends Component {
state = {
formData: null
}
callbackFormData = (formData) => {
console.log(formData);
this.setState({formData: formData});
}
render() {
return (
<Switch>
<Route path='/askQuestion' render={() => <AskQuestion callbackFormData={this.callbackFormData}/> } />
<Route path='/singleQuestion' render={() => <SingleQuestion formData={this.state.formData}/>} />
</Switch>
);
}
}
export default App;
//AskQuestion
import React, { Component } from "react";
import { withRouter } from 'react-router-dom';
class AskQuestion extends Component {
redirect = () => {
this.props.history.push("singleQuestion");
};
submitHandler = () => {
let title = document.getElementById('title').value;
if(title !== '')
this.props.callbackFormData(title);
this.redirect();
}
render() {
return (
<React.Fragment>
<input id="title" />
<button onClick={this.submitHandler}>Post Question</button>
</React.Fragment>
)
}
}
export default withRouter(AskQuestion);
// SingleQuestion.js
import React, { Component } from "react";
class SingleQuestion extends Component {
render() {
return <h1>Title:- {this.props.formData}</h1>;
}
}
export default SingleQuestion;
i hope it helps!
If you want to use state form in SingleQuestion component after called redirect, try this.
redirect = () => {
this.props.history.push('/SingleQuestion', {
form: this.state.form
});
}
After then check console.log(this.props.history.location.state.form)

Changes are not reflected in UI in react

When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
import React from 'react';
import moment from 'moment';
import CommentForm from './CommentForm';
import CommentList from './CommentList';
import CommentModal from './CommentModal';
import { connect } from 'react-redux';
import { startAddComment, startAddLike, startRemoveLike } from
'../actions/post';
import { Link } from 'react-router-dom';
import UserInfo from './UserInfo';
class PostListItem extends React.Component{
constructor(props){
super(props);
this.state = {
isliked: false,
commentM: undefined,
likes: this.props.likes
}
}
componentDidMount(){
if(this.props.likes.includes(this.props.user.uid)){
this.setState(() => ({isliked:true}));
}
}
onClickedLike = () =>{
if(this.state.isliked === false){
this.props.dispatch(startAddLike(this.props._id));
this.setState(()=>{
console.log(this.props);
return{
isliked:true
}
});
} else{
this.props.dispatch(startRemoveLike(this.props._id));
this.setState(()=>({isliked:false}));
}
}
openModal = () =>{
this.setState({commentM: this.props.comments});
}
closeModal = () =>{
this.setState(({commentM: undefined}));
}
render(){
return(
<div className="post">
<div className="post__header">
<UserInfo user={this.props.author}
time={this.props.createdAt}/>
{
(this.props.user.uid === this.props.author.uid)?
<Link to={`/edit/${this.props._id}`}
className="post__edit">
Edit</Link>:''
}
{/* <p className="post__time">
{moment(this.props.createdAt).fromNow()}</p> */}
</div>
<div className="post__caption">{this.props.caption}</div>
<img src={this.props.content} className="post__content"/>
<div className="post__extra">
<div className="post__lc">
<button className="post__button"
onClick={this.onClickedLike}
>{this.state.isliked? <i className="fas fa-futbol"></i>
: <i className="far fa-futbol"></i>}
</button>
<button className="post__button"
onClick={this.openModal}><i className="far fa-
comment"></i>
</button>
</div>
{this.props.likes.length !== 0 && <p className="post__like">
{this.props.likes.length} {this.props.likes.length === 1? 'like':'likes'}
</p>} // likes count is not changing while removing the like(ui only)
<CommentModal
commentM={this.state.commentM}
closeModal={this.closeModal}/>
<CommentForm onSubmit={(comment) => {
this.props.dispatch(startAddComment(this.props._id,
comment));
}} />
{this.props.comments && <CommentList comments=
{this.props.comments}/>}
</div>
</div>
);
}
};
const mapStateToProps = (state) => {
return{
user: state.auth
}
}
export default connect(mapStateToProps)(PostListItem);

Creating onClick event for datalist option in React

I've made a Twitch API widget which you can see here: https://twitch-react-drhectapus.herokuapp.com/
At the moment, any time you search for something, there will be a list of suggestions. I'd like to make it so that when you click on one of the datalist options it will search for that user, rather than having to click on the 'Search' button. Basically the same search function as google has.
How do I go about implementing this?
Code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUser, fetchSuggestions } from '../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {
term: ''
};
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onInputChange(event) {
this.setState({
term: event.target.value
});
setTimeout( this.props.fetchSuggestions(event.target.value), 300);
}
renderSuggestions(sug, i) {
return (
<option key={i} value={sug.display_name} />
)
}
onFormSubmit(event) {
event.preventDefault();
this.props.fetchUser(this.state.term);
this.setState({
term: ''
});
}
render() {
const { error, suggestions } = this.props;
return (
<form
className='input-group'
onSubmit={this.onFormSubmit}>
<input
className='form-control'
placeholder='Search for a Twitch user'
value={this.state.term}
onChange={this.onInputChange}
list='suggestions' />
<span className='input-group-btn'>
<button className='btn btn-primary'>
Search
</button>
</span>
<datalist id='suggestions'>
{suggestions.map(this.renderSuggestions)}
</datalist>
</form>
// {/* {error && <div className='alert alert-danger'>{error}</div>} */}
)
}
}
function mapStateToProps({ error, suggestions }) {
return { error, suggestions };
}
export default connect(mapStateToProps, { fetchUser, fetchSuggestions })(SearchBar);

Resources