State changes but doesn't call render function of parent component - reactjs

# Its is my parent component i have dispatch the action from child component and state changes but render function of parent component does not called .
In child component every time when i click on checkbox then i dispatch the action for updating the state in reducer and i received new state in mapStatetoprop but it does not update the UI
const propTypes = {
teamPlayers : PropTypes.array.isRequired,
matchesData: PropTypes.object.isRequired,
isfetchingTeamPlayer: PropTypes.bool.isRequired
};
class CreateTeam extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedPlayerIDs : [],
count:0,
isforward:false,
show:false,
message:''
}
this.toggleChecked = this.toggleChecked.bind(this);
this.forwardRoute = this.forwardRoute.bind(this);
this.previousRoute = this.previousRoute.bind(this);
}
componentWillMount() {
this.props.createTeam(this.props.matchID);
}
renderPlayerCard() { console.log(this.props.teamPlayers)
let count = 0;
return this.props.teamPlayers.map((player) => {
if(player.isChecked){
count+=1;
}
let mtype = '';
return (
<PlayerCard
key={player.id}
player={player}
mtype={mtype}
count={count}
selectedPlayerIDs={this.state.selectedPlayerIDs}
triggerChanges={this.toggleChecked}
/>
);
})
}
render () {
if(!this.props.isfetchingTeamPlayer && !this.props.isPlayersFetching ){
return <h1>Loading...</h1>;
}
console.log("selected5Players"+this.props.selected5Players)
return(
<div>
<div className="card">
<div className="container-grey">
<div className="timer2">
<table className="timer-table2">
{
this.props.matchesData.end_time ?
<Counter
endDate={this.props.matchesData.end_time}
/> : null
}
</table>
</div>
<table className="team-table2">
<tr className="match-team">
<td className='team-logo-box'>
<div className="white-box">
{
this.props.matchesData.hasOwnProperty('teams') ?
<img className="team-logo2" alt="Team1"
src={this.props.matchesData.teams.home_team.flag_path}/>
:null
}
</div>
</td>
<td className="team-name2 left">{this.props.matchesData.teams.away_team.short_name}</td>
<td><img className="versus2" alt="versus" src={vs}/></td>
<td className="team-name2 right">{this.props.matchesData.teams.away_team.short_name} </td>
<td className='team-logo-box'>
<div className="white-box">
<img className="team-logo2" alt="Team2"
src={this.props.matchesData.teams.away_team.flag_path}/>
</div>
</td>
</tr>
</table>
</div>
<div className="player-list">
<table className="timer-table2">
<tbody>
{this.renderPlayerCard()}
</tbody>
</table>
</div>
</div>
<div className="foot-container">
</div>
</div>
);
}
}
CreateTeam.propTypes = propTypes;
const mapStateToProps = (state,ownProps) => {
// I am getting updated state here but doesn't call the render function//
console.log("state Changes but does not call the render function of this component")
return {
matchID: ownProps.params.teamID,
selected5Players: state.matchesTeam.selected5Players,
teamPlayers: selectedCheckedplayers(state),
matchesData: state.matchesTeam.matchesData,
isfetchingTeamPlayer: state.matchesTeam.isfetchingTeamPlayer,
isPlayersFetching: state.matchesTeam.isPlayersFetching
}
};
Below the code of child component where i dispatch the action
here i dispatching the action on every checkbox (handleChange() function ) see below
const propTypes = {
player: PropTypes.object.isRequired,
};
class PlayerCard extends React.Component {
handleChange(evt,id,isSelected) {
this.props.togglePlayersChecked({"player":this.props.player,"status":!isSelected})
}
render() {
return (
<tr>
<td className="batsmen-pic">
<img alt='batsmen' className='batsmen-picture' src={this.props.player.photo_url} />
</td>
<td className="batsmen-details">
<div className="batsmen-name left">
<div className="first-name">{this.props.player.name}</div>
</div>
</td>
<td className="batsmen-checkbox-holder">
<div>
<input className="batsmen-checkbox"
type="checkbox"
onChange={event => this.handleChange(event, this.props.player,this.props.player.isChecked)}
value={this.props.player.id}
checked={this.props.player.isChecked }
/>
</div>
</td>
</tr>
);
}
}
PlayerCard.propTypes = propTypes;
const mapStateToProps = (state,ownProps) => ({
selected5Players: state.matchesTeam.selected5Players,
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
togglePlayersChecked
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(PlayerCard);
below the code of Reducer function of this action
const createTeamReducer = createReducer({
[createTeam]: (state) => ({
...state,
isfetchingTeamPlayer: true,
}),
[createTeam.error]: (state, error) => ({
...state,
teamPlayerError: error,
isfetchingTeamPlayer: false,
isPlayersFetching:true
}),
[createTeam.success]: (state, payload) => {
const teamPlayers = normalize(payload.players);
const matchesData = {...payload.match_data};
const isSaved = true;
return { ...state,matchesData, teamPlayers, isSaved ,isRefreshingTeamPlayer: false };
},
[togglePlayersChecked]: (state, payload) => { console.log(payload)
let teamPlayers = state.teamPlayers;
const isSaved = false;
let selected5Players = state.selected5Players;
if (payload.status) {
if (selected5Players.length >= 5){
//alert("You can't select more then five");
return { ...state, teamPlayers,selected5Players};
}else {
const index = teamPlayers.findIndex((player) => player.id === payload.player.id);
teamPlayers[index].isChecked = true;
selected5Players.push(payload.player);
}
} else {
const index = teamPlayers.findIndex((player) => player.id === payload.player.id);
console.log(index);
var c = selected5Players.findIndex((val) => val.id === payload.player.id);
selected5Players.splice(c,1);
console.log(selected5Players)
teamPlayers[index].isChecked = false;
}
return { ...state, teamPlayers,selected5Players,isSaved};
},
[get5player]:(state,payload) => {
const selectedTeamplayer = [...state.selected5Players];
const istwoSelected = true;
console.log(selectedTeamplayer);
return { ...state, selectedTeamplayer,istwoSelected};
},
[get5Batsmen2BestBatsmen]:(state,payload) => {
let select5BatsmenAnd2BestBatsmen = [];
return { ...state, select5BatsmenAnd2BestBatsmen};
},
[deleteTeam]:(state,payload) => {
let selected5Players = [];
let select2batsmen = [];
let teamPlayers = [];
const isSaved = true;
const select5BatsmenAnd2BestBatsmen = [];
return {...state, select2batsmen, selected5Players,teamPlayers,isSaved,select5BatsmenAnd2BestBatsmen};
}
}, initialState);
export default createTeamReducer;

You might be mutating the state inside reducer instead of returning new state. Hence the changes are not detected.

Related

How to change let value onClick in React

My default value is null (let activestatus = "";), but I want it to change on click to be:
let activestatus = "?IsActive=0";
I am getting value on click (as seen in console), but the value is not passed in "let activestatus".
class App extends Component {
state = {
reservations: [],
};
componentWillMount() {
let activestatus = "";
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.activestatus = e.target.value;
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>
Can you try to have activeStatus as part of your state? Also if you want to refresh the data from the api based on this field, then should probably use componentDidUpdate that runs on state changes.
class App extends Component {
state = {
reservations: [],
activestatus: ""
};
componentWillMount() {
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`
Thanks guys, both were helpful.
Solution:
class App extends Component {
state = {
reservations: [],
activestatus: "",
};
componentDidUpdate() {
axios
.get(
"https://localhost:44307/api/GetReservations/" +
`${this.state.activestatus}`
)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`

Api data returns to 0 after information is called (React)

I am fetching information about stocks in componentDidUpdate in React. The information that I want to fetch renders but after a few seconds the information reverts back to 0. I don't know why it is happening and I have tried to fetch it in componentDidMount first but the same thing keeps happening. I don't know how to go about solving this problem. Can someone point me in the right direction?
constructor(props) {
super(props);
this.state = {
userInput: '',
stockSymbol: [],
marketData: [],
isLoaded: false,
symbol1: [],
};
}
typeSymbol = e => {
this.setState({
userInput: e.target.value.toUpperCase(),
});
};
componentDidMount() {
const { userInput } = this.state;
const urls = [
`https://api.iextrading.com/1.0/ref-data/symbols`,
`https://api.iextrading.com/1.0/tops`,
];
let requests = urls.map(url => fetch(url));
Promise.all(requests)
.then(responses => {
return Promise.all(responses.map(response => response.json()));
})
.then(responses => {
this.setState({
stockSymbol: responses[0],
marketData: responses[1],
});
});
}
componentDidUpdate(prevProps, prevState, snapShot) {
const { userInput, symbol1 } = this.state;
if (prevState.userInput !== userInput) {
fetch(
`https://finnhub.io/api/v1/quote?symbol=${userInput}&token=brjo6knrh5r9g3ot7150`,
)
.then(res => res.json())
.then(responses => this.setState({ symbol1: responses }));
}
}
render() {
const { stockSymbol, userInput, marketData, symbol1 } = this.state;
const filteredSymbols = stockSymbol.filter(sym => sym.symbol === userInput);
const foundMarket = marketData.find(market => market.symbol === userInput);
const objData = () => {
for (const stockData in symbol1) {
console.log(`${stockData}: ${symbol1[stockData]}`);
}
};
objData();
const clock = new Date().toLocaleString();
return (
<div className="enterstock">
<div className="fields">
<span className="clock">{clock}</span>
<h1 className="title">Enter Stock Symbol</h1>
<input
type="text"
className="symfields"
name="symbolname"
onChange={this.typeSymbol}
/>
</div>
{filteredSymbols.map((stock, i) => {
return (
<div className="stockings">
<div className="named">
<h2 className="symbol">{this.state.userInput}</h2>
<h2 className=" name" key={i}>
{stock.name}
</h2>
</div>
{
<h2 className="stocked price" key={i}>
Price: {symbol1.c}
</h2>
}
</div>
);
})}
,
</div>
);
}

Reactjs not re-rendering update received from WebSockets

I am using WebSockets to update upvotes on comments in React. I am receiving comment updates in logs of different client instances. However, React does not render the updates to upvotes.
Code I am trying:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
class Comment extends Component {
constructor(props){
super(props);
this.upvotes = React.createRef();
this.downvotes = React.createRef();
this.handleUpvote = this.handleUpvote.bind(this);
this.handleDownvote = this.handleDownvote.bind(this);
}
handleUpvote(){
console.log(this.props);
const json = { type: 'upvote' };
json.data = this.props;
json.data.comment.upvotes++;
console.log(json);
this.props.socket.send(JSON.stringify(json));
}
handleDownvote(){
this.downvotes.current.innerHTML++;
console.log(this.downvotes.current.innerHTML);
}
render() {
return (
<tr>
<td>{this.props.comment.user.firstName} {this.props.comment.user.lastName}</td>
<td>{this.props.comment.content }</td>
<td> <span ref={this.upvotes}>{this.props.comment.upvotes}</span> <button onClick={this.handleUpvote}>Upvote</button> </td>
<td> <span ref={this.downvotes}>{this.props.comment.downvotes}</span> <button onClick={this.handleDownvote}>Downvote</button> </td>
</tr>
)
}
}
export default class ListComments extends Component {
constructor(props){
super(props);
this.state = { comments: [] }
}
componentDidMount(){
axios.get('http://localhost:5000/api/comments/')
.then(resp => this.setState({ comments : resp.data }))
.catch(err => console.log(err));
}
componentWillReceiveProps(nextProps){
const data = JSON.parse(nextProps.comment);
console.log(data.data);
if(data.type === "upvote"){
// const a = this.state.comments;
// a.forEach(comment => {
// if(comment._id == data.data.comment._id){
// comment = data.data.comment
// }
// });
// this.setState({ comments : a })
this.setState(prevState => {
// Get previous state
const { comments } = prevState;
// Add new item to array
comments.forEach(comm => {
if(comm._id == data.data.comment._id){
comm = data.data.comment
}
});
// Return new state
return { comments };
});
}
else if(data.type === "comment"){
this.setState({ comments : [data.data, ...this.state.comments] })
}
}
commentList() {
return this.state.comments.map(currentcomment => {
return <Comment comment={currentcomment} socket={this.props.actions} key={currentcomment._id}/>;
})
}
render() {
return (
<div>
<h3>Comments</h3>
<table className="table">
<thead className="thead-light">
<tr>
<th>Username</th>
<th>Content</th>
<th>Upvotes</th>
<th>Downvotes</th>
</tr>
</thead>
<tbody>
{ this.commentList() }
</tbody>
</table>
</div>
);
}
}
Outputs I am getting -
Client one with 3 upvotes to question 1
Client 2 with updates to upvotes received in console, not rendred in actual comment

React-Redux: Cannot read property 'map' of undefined when deleting an item

I have an error after clicking the delete button saying:
Cannot read property 'map' of undefined.
I'm new in React Redux JS.
Please see my code below of my component reducers and actions:
Post.js
class Post extends Component {
constructor(){
super();
this.deletePost = this.deletePost.bind(this);
}
deletePost(postId){
this.props.deletePost(postId);
}
render(){
const postItems = this.props.posts.map(post => (
<div key={post.id} className="row">
<div className="container">
<h3>{post.title}</h3>
<p>{post.body}</p>
<button
onClick={() =>this.deletePost(post.id)}
className="btn btn-danger">
Delete
</button>
</div>
</div>
))
const divStyle = {
padding: '15px',
}
return (
<div style={divStyle}>
<PostForm />
<hr/>
{postItems}
</div>
)
}
}
const mapStateToProps = state => ({
posts: state.posts.items,
newPost: state.posts.item
})
export default connect(mapStateToProps, { fetchPosts, deletePost })(Post);
PostAction.js (Here is my delete action. I am using jsonplaceholder API post.)
export const deletePost = (postId) => dispatch => {
fetch('https://jsonplaceholder.typicode.com/posts/'+postId, {
method: 'DELETE',
})
.then(dispatch({
type: DELETE_POST,
payload: postId
}));
}
PostReducer.js (This is my reducer.)
case DELETE_POST:{
const newState = Object.assign([], state);`enter code here`
const filteredItems = newState.items.filter(items => {
return items.id != action.payload;
});
return filteredItems;
}
case DELETE_POST:{
const { items } = state;
const filteredItems = items.filter(items => {
return items.id != action.payload;
});
return {
...state,
items: [ ...filteredItems ]
};
}
Yes just replace
return filteredItems; to return { items: filteredItems }
But please can you check my code if it's correct. Thanks

How to correctly bind React onClick event with Redux?

Basically there's no sign that the event is binded somewhere and it's not firing. Here's the Component
class AgendaPointsList extends React.Component {
constructor(props) {
super(props);
this.onAgendaPointClick = this.props.onAgendaPointClick.bind(this);
}
render() {
let items = this.props.agenda_points.map((a, i) => {
return <AgendaPoint key={i} agenda_point={a} index={i} onClick={this.onAgendaPointClick} />
})
console.log(this.props)
return (
<table>
<tbody>
{items}
</tbody>
</table>
);
}
}
The console.log(this.props) outputs:
Object
item_point: Object
item_points: Array[4]
onItemPointClick: onItemPointClick(id)
onModalCloseClick: onModalCloseClick(id)
store: Object
storeSubscription: Subscription
__proto__: Object
Here's the redux component:
const OPEN_AGENDA_POINT = 'meeting/OPEN_AGENDA_POINT'
const CLOSE_AGENDA_POINT = 'meeting/CLOSE_AGENDA_POINT'
const initialState = {
modal_is_open: false,
point_id: 0,
point_data: {}
}
const openAgendaPoint = function (id) {
return {
type: OPEN_AGENDA_POINT,
id: id
}
}
const closeAgendaPoint = function (id) {
return {
type: CLOSE_AGENDA_POINT,
id: id
}
}
const agendaPointsReducer = function (state = initialState, action) {
switch (action.type) {
case OPEN_AGENDA_POINT: {
state.modal_is_open = true,
point_id = action.id
}
case CLOSE_AGENDA_POINT: {
state.modal_is_open = false
}
default:
return state
}
}
const agendaPointsUiStateProps = (state) => {
return {
agenda_point: state.point_data
}
}
const agendaPointsUiActions = (dispatch) => {
return {
onAgendaPointClick: (id) => {
console.log(id)
dispatch(openAgendaPoint(id))
},
onModalCloseClick: (id) => {
dispatch(closeAgendaPoint(id))
}
}
}
const store = Redux.createStore(
agendaPointsReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
// Usage:
const AgendaPointsList = connectWithStore(
store,
AgendaPointsList,
agendaPointsUiStateProps,
agendaPointsUiActions
)
That's the child component:
class AgendaPoint extends React.Component {
render() {
return (
<tr>
<td>{ this.props.index + 1 }</td>
<td>{ this.props.agenda_point.title}</td>
<td>6</td>
<td>{ this.props.agenda_point.agenda_time } min</td>
</tr>
);
}
}
I tried multiple ways of binding the event:
onClick={this.props.onAgendaPointClick.bind(a.id, this)
onClick={this.props.onAgendaPointClick(a.id, this).bind(this)
onClick={() => this.props.onAgendaPointClick(a.id))
Non seem to work.
Using this for reac-redux connect wrapper to pass in store. This is running on Ruby on Rails Sprockets beta4.
What is the correct way of doing this?
You want the on click to be on you tag.
With the following code change you event will be triggerd:
class AgendaPoint extends React.Component { render() {
return (
<tr onClick={this.props.onClick}>
<td>{ this.props.index + 1 }</td>
<td>{ this.props.agenda_point.title}</td>
<td>6</td>
<td>{ this.props.agenda_point.agenda_time } min</td>
</tr>
); } }
Try binding the event in your ItemList constructor:
constructor(props) {
super(props);
this.onItemClick = this.onItemClick.bind(this);
}
Then in your ItemList render function ...
let items = this.props.agenda_points.map((a, i) => {
return <Item key={i} agenda_point={a} index={i} onClick={this.props.onItemClick} />
})
This assumes that the onItemClick function is defined in ItemList parent, and is being passed in as a prop.

Resources