I'm new in React and I'm using Semantic-ui-react. I'm trying to use the Dropdown.
When I want to get my value from the dropdown and call my function. My event get some proxy object.
handleTagChange(e) {
console.log("handleTagChange");
console.log(e);
}
But if I add something else like test in the function, the e.target.value works and test is the proxy object. Why is that?
handleTagChange(test, e) {
console.log("handleTagChange");
console.log(test);
console.log(e);
}
TagFilter.js
import React, { PropTypes } from 'react';
import { Dropdown } from 'semantic-ui-react'
export default class TagFilter extends React.PureComponent {
render() {
console.log(this.props);
const options = [
{ "text": "Admin stuff", "value": "admin stuff" },
{ "text": "Frontend", "value": "frontend" },
{ "text": "JS", "value": "js" },
{ "text": "Mucking about", "value": "mucking about" },
{ "text": "React", "value": "react" }
];
return (
<Dropdown placeholder='Skills' fluid selection options={options} onChange={this.props.handleTagChange} />
);
}
}
Employee.js
import React, { PropTypes } from 'react';
import { Image, List } from 'semantic-ui-react';
import TagFilter from './TagFilter';
import ProductFilter from './ProductFilter';
import MyModal from './Modal';
export default class Employees extends React.Component {
//static defaultProps = {
//}
constructor() {
super();
this.closeModal = this.closeModal.bind(this);
this.handleTagChange = this.handleTagChange.bind(this);
this.handleProductChange = this.handleProductChange.bind(this);
}
state = {
tagsFilterValue: null,
productsFilterValue: null,
employeeDetails: null,
openModal: false
}
handleTagChange(e) {
console.log("handleTagChange");
console.log(e);
}
handleProductChange(e) {
let productValue = e.target.value;
this.setState({productsFilterValue: productValue});
}
handleEmployeeClick(name, e) {
this.setState({employeeDetails: name});
this.setState({openModal: true});
}
closeModal() {
this.setState({openModal: false});
}
render() {
let filteredEmployees = this.props.data.filter(
(employee) => {
// If state tagsFilterValue and productsFilterValue is not null
if (this.state.tagsFilterValue && this.state.productsFilterValue) {
return employee.tags.indexOf(this.state.tagsFilterValue) !== -1 && employee.products.indexOf(this.state.productsFilterValue) !== -1;
}
// If state tagsFilterValue is not null
else if (this.state.tagsFilterValue) {
return employee.tags.indexOf(this.state.tagsFilterValue) !== -1;
}
// If state productsFilterValue is not null
else if (this.state.productsFilterValue) {
return employee.products.indexOf(this.state.productsFilterValue) !== -1;
}
else {
return employee;
}
}
);
let employeeDetails = this.props.data.filter(
(employee) => {
return employee.name.indexOf(this.state.employeeDetails) !== -1;
}
);
return (
<div>
{ employeeDetails.map((employee) => (
<MyModal employeeDetails={employee} closeModal={this.closeModal} openModal={this.state.openModal} />
))}
<div className="ui grid">
<TagFilter handleTagChange={this.handleTagChange} tagsFilterValue={this.state.tagsFilterValue} />
<ProductFilter handleProductChange={this.handleProductChange} productsFilterValue={this.state.productsFilterValue} />
</div>
<List>
{ filteredEmployees.map((employee) => (
<List.Item key={employee.name}>
<div className="ui card">
<div className="image">
<img alt="User avatar" src={employee.image}/>
</div>
<div className="content">
<a className="header" onClick={this.handleEmployeeClick.bind(this, employee.name)}>{employee.name}</a>
<div className="meta">{employee.title}</div>
</div>
</div>
</List.Item>
))}
</List>
</div>
);
}
}
This is happening because most semantic-ui-react events return 2 objects, and the second one is what contains the data that you need to handle the event.
There's a more detailed explanation in a GitHub issue here:
https://github.com/Semantic-Org/Semantic-UI-React/issues/638#issuecomment-252035750
Related
I am using react to build my app and on the post component there are 3 other child components that are been called in a map function while passing the post props.
On the list component when a user clicks on the like button the post tends to reload, and that is not what I want.
This is my post parent component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
class Posts extends Component {
constructor(props) {
super(props)
this.state = {
sidebaropen: false,
test: '',
posts: []
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.post.posts.length > 0) {
this.setState({ posts: nextProps.post.posts })
console.log('updated')
}
}
componentDidMount() {
this.props.getPosts();
socket.on('posts', data => {
console.log("resiving :" + JSON.stringify(data))
if (Object.keys(this.state.posts).length > 0 && Object.keys(data).length >
0) {
this.setState({ posts: [data[0], ...this.state.posts] })
} else {
this.setState({ posts: data })
}
})
socket.on('id', data => {
console.log(data)
})
console.log('mounted post')
}
}
render(){
const { loading } = this.props.post;
const { posts, } = this.state;
let closebtn
let postContent;
if (posts === null || loading) {
postContent = <Spinner />;
} else {
postContent = <PostFeeds posts={ posts } />;
}
if (this.state.sidebaropen) {
closebtn = <button className='close-toggle-btn' onClick =
{ this.closetoggleclickhandle } />
}
return (
<div className= "post_wrapper" >
<Postsidebar show={ this.state.sidebaropen } />
< div className = "" >
{ postContent }
< /div>
{ closebtn }
<TiPlus className='creat-post-toggle-btn icons' onClick =
{ this.toggleclickhandle } />
</div>
)
}
}
Posts.propTypes = {
getPosts: PropTypes.func.isRequired,
post: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
post: state.post
})
export default connect(mapStateToProps, { getPosts })(Posts);
and this is the first child component
import React, { Component } from 'react';
import PostItem from './PostItem';
class PostFeeds extends Component {
componentDidMount() {
//this.setState({ test : 'mounted'})
console.log('mounted feed')
}
render() {
const { posts } = this.props;
//console.log(posts)
return posts.map(post => <PostItem key={ post._id } post = { post } />);
}
}
postItem.js its i little kind of rough
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { deletePost, addLike, removeLike, bookmark } from "../../actions/postsActions";
import Postimg from './Postimg';
import { MdBookmarkBorder ,/**MdBookmark */} from "react-icons/md";
import {AiFillDislike, AiOutlineLike, AiFillDownSquare} from 'react-icons/ai'
import { TiHeartOutline, TiHeartFullOutline, TiMessage, TiDelete } from "react-icons/ti";
class PostItem extends Component {
onDeleteClick(id){
this.props.deletePost(id);
}
componentWillMount() {
console.log( 'mounted item')
//console.log(window.scrollTo(0, localStorage.getItem('scrollpossition')))
}
onLikeClick(id){
this.props.addLike(id);
// window.scrollTo(0, localStorage.getItem('scrollpossition'))
window.location.href = '/feed'
}
onUnlikeClick(id){
this.props.removeLike(id);
// window.scrollTo(0, localStorage.getItem('scrollpossition'))
window.location.href = '/feed'
}
findUserLike(likes) {
const { auth } = this.props;
if(likes.length > 0){
if(likes.filter(like => like.user === auth.user.id).length > 0) {
return true;
} else {
return false;
}
}
}
findUserDislike(dislikes) {
const { auth } = this.props;
if(dislikes.length > 0){
if(dislikes.filter(dislike => dislike.user === auth.user.id).length > 0) {
return true;
} else {
return false;
}
}
}
onBookmark (id){
this.props.bookmark(id)
}
render() {
const { post, auth, showActions } = this.props;
let ifAlreadyliked;
let ifAlreadydisliked;
let postimg;
let postText;
let profileimg
let topic = ''
if(post.user)
{
if(post.user.profileImageData){
profileimg = <Link to={`/profile/${post.profile.handle}`}><img src={post.profile.profileImageData} alt='' /></Link>
}else{
profileimg = <img src='/assets/images/user-4.png' alt='pip' />
}
if(this.findUserLike(post.likes)){
ifAlreadyliked = <TiHeartFullOutline className= 'icons like-color'/>
}else{
ifAlreadyliked = <TiHeartOutline className= 'icons'/>
}
if(this.findUserDislike(post.dislikes)){
ifAlreadydisliked = <AiFillDislike className= 'icons yellow'/>
}else{
ifAlreadydisliked = <AiOutlineLike className= 'icons' onClick={this.onUnlikeClick.bind(this, post._id)}/>
}
}
if(post.Topic){
topic = <div className= ''><small><b style={{color:'#ff8d00'}}>< AiFillDownSquare />{post.Topic}</b></small></div>
}
if(post.postImageData !== '' && post.postImageData !== null && post.postImageData !== undefined)
{
postimg = <Postimg imageSrc = {post.postImageData} imgAlt = {''}/>
}
if(post.text !== '' || post.text === null)
{
postText = <div className='feed_text'>{post.text}</div>
}
return (
<div className="feed_card">
<div className="feed_header">
<div className="feed-profile-img">{profileimg}</div>
<div className="feed-handle-text">{post.name}</div>
<div className='v-spacer'/>
<div className="time-stamp"><small>{new Date (post.date).toLocaleString ('en-US', {hour: 'numeric', hour12: true, minute: 'numeric', month: 'long', day: 'numeric' } )} </small></div>
</div>
<div className="feed-body-container">
<div>
{topic}
{postimg}
{postText}
<div className='mini_feed_footer'>
<small>{post.likes.length} likes. {post.comments.length} comments. {post.dislikes.length} dislikes.</small>
</div>
{ showActions ? (
<div className='feed_footer'>
<div onClick={this.onLikeClick.bind(this, post._id)} type="button" className="btn btn-light mr-1">
<div className='feed-icon-mini-container'>
{ifAlreadyliked}
</div>
</div>
<div className='spacer'/>
{ifAlreadydisliked}
<div className='spacer'/>
<Link to={`/post/${post._id}`} className='header-brand'>
<TiMessage className='icons'/>
</Link>
<div className='spacer'/>
{ post.user === auth.user.id ? (
<TiDelete
onClick={this.onDeleteClick.bind(this, post._id)}
className="icons red"
/>
) : <MdBookmarkBorder
onClick={this.onBookmark.bind(this, post._id)}
className="icons blue"
/> }
</div>) : null}
</div>
</div>
</div>
);
}
}
PostItem.defaultProps = {
showActions: true
}
PostItem.propTypes = {
post: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
deletePost: PropTypes.func.isRequired,
addLike:PropTypes.func.isRequired,
removeLike:PropTypes.func.isRequired,
bookmark:PropTypes.func.isRequired
};
const mapStateToProps = state => ({
auth: state.auth
})
export default connect(mapStateToProps, {deletePost, addLike,bookmark, removeLike})(PostItem);
Don't use window object for navigation (Major) as this causes reload. Make your handlers arrow functions (minor).
onLikeClick = id => {
this.props.addLike(id);
// window.scrollTo(0, localStorage.getItem('scrollpossition'))
this.props.history.push("/feed");
};
onUnlikeClick = id => {
this.props.removeLike(id);
// window.scrollTo(0, localStorage.getItem('scrollpossition'))
this.props.history.push("/feed");
};
Also if /feed is the same page then remove it all together, no need for it.
I have a course page with a list of students as buttons. On click, the button should render ShowStudentInfo but my ShowStudentInfo component is not rendering on click when nested inside (if state.isClicked). Outside of the the conditional it works fine but I need that conditional otherwise everything will show up on course page render.
Main Course Component
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions/index';
import { Redirect } from 'react-router';
import { Link } from 'react-router-dom';
import ShowStudentInfo from '../ShowStudentInfo/ShowStudentInfo'
class CoursePage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
course: {},
student: {},
isClicked: false
};
console.log(this.props.match.params.cuid)
this.onClick = this.onClick.bind(this)
}
onClick(event) {
event.preventDefault()
console.log(this.state.isClicked)
this.setState({
isClicked: !this.state.isClicked
})
}
componentDidMount() {
this.props.dispatch(actions.getCourse(this.props.match.params.cuid));
this.props.dispatch(actions.getStudents());
}
render() {
let studentList = this.props.student
const students = Object.keys(studentList).map(student => studentList[student])
const currentStudents = students.map(student => {
if ((this.props.match.params.cuid) == student.courses) {
return (
<p>
<button className="students" id={student._id} onClick={this.onClick}>{student.firstName} {student.lastName}</button>
</p>
)
if (this.state.isClicked) {
return (
<div className="student-info">
<ShowStudentInfo firstName={student.firstName}
lastName={student.lastName} phoneNumber={student.phoneNumber} />
</div>
)
}
}
})
return (
<div>
<h1>{this.props.course.name}</h1>
<Link to={`/addStudent/${this.props.match.params.cuid}`}> Add a new student</Link>
<div className="studentList">Your students{currentStudents} </div>
</div>
);
}
}
const mapStateToProps = (state, props) => {
return {
course: state.course.course,
student: state.student.students
}
}
export default connect(mapStateToProps)(CoursePage)
My ShowStudentInfo component
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions/index';
import { Redirect } from 'react-router';
import { Link } from 'react-router-dom';
class ShowStudentInfo extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
student: {
firstName: '',
lastName: '',
phoneNumber: ''
},
isClickedEdit: false,
isClickedDelete: false
}
this.isClickedEdit = this.isClickedEdit.bind(this)
this.isClickedDelete = this.isClickedDelete.bind(this)
}
isClickedEdit(event) {
this.setState({
isClickedEdit: true
})
}
isClickedDelete(event) {
this.setState({
isClickedDelete: true
})
}
render() {
return (
<div className="student-info-container">
<p>Name: {this.props.firstName} {this.props.lastName}</p>
<p>Phone Number: {this.props.phoneNumber}</p>
</div>
)
}
}
if (this.state.isClicked) {
return (
<div className="student-info">
<ShowStudentInfo firstName={student.firstName}
lastName={student.lastName} phoneNumber={student.phoneNumber} />
</div>
)
}
is the most important part to look at and the info is rendering normally without the onClick conditional.
Your map function contains 2 return functions, while the first return will cause it to go to the next item in the current iteration process
if ((this.props.match.params.cuid) == student.courses) {
return (
<p>
<button className="students" id={student._id} onClick={this.onClick}>{student.firstName} {student.lastName}</button>
</p>
)
// this will never hit in case the previous statement is evaluates to true
if (this.state.isClicked) {
return (
<div className="student-info">
<ShowStudentInfo firstName={student.firstName}
lastName={student.lastName} phoneNumber={student.phoneNumber} />
</div>
)
}
}
To achieve what you want to do, (i am guessing you wish it as part of the first return statement), you could do it like so
if ((this.props.match.params.cuid) == student.courses) {
return (
<p>
<button className="students" id={student._id} onClick={this.onClick}>{student.firstName} {student.lastName}</button>
{ this.state.isClicked && <div className="student-info">
<ShowStudentInfo firstName={student.firstName}
lastName={student.lastName} phoneNumber={student.phoneNumber} />
</div> }
</p>
)
}
Be warned: This will show the students info as part of the p tag for all the students on the screen, I don't see where you restrict showing the users info for the one clicked student.
As another side note, are you sure you wish to comparse an object of courses with a cuid parameter?
This is just a little refactoring in your logic :) hope it helps you.
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions/index';
import { Redirect } from 'react-router';
import { Link } from 'react-router-dom';
import ShowStudentInfo from '../ShowStudentInfo/ShowStudentInfo'
class CoursePage extends React.Component {
state = {
course: {},
student: {},
isClicked: false
};
onClick = (event) => {
event.preventDefault()
console.log(this.state.isClicked)
this.setState({
isClicked: !this.state.isClicked
})
}
getCurrentStudents = (students) => {
const { match } = this.props
const { isClicked } = this.state
return students.map(student => {
if (match.params.cuid == student.courses) {
return (
<div>
<p><button className="students" id={student._id} onClick={this.onClick}>
{student.firstName} {student.lastName}
</button></p>
{isClicked && this.getStudentInfo(student) }
</div>
)
}
})
}
getStudentInfo = (student) => (
<div className="student-info" >
<ShowStudentInfo
firstName={student.firstName}
lastName={student.lastName}
phoneNumber={student.phoneNumber} />
</div>
)
componentDidMount() {
let { match, dispatch } = this.props
dispatch(actions.getCourse(match.params.cuid));
dispatch(actions.getStudents());
}
render() {
let { studentList, match, course } = this.props
const students = Object.keys(studentList).map(student => studentList[student])
const currentStudents = this.getCurrentStudents(students)
return (
<div>
<h1>{course.name}</h1>
<Link to={`/addStudent/${match.params.cuid}`}> Add a new student</Link>
<div className="studentList">Your students{currentStudents} </div>
</div>
);
}
}
const mapStateToProps = (state, props) => {
return {
course: state.course.course,
student: state.student.students
}
}
export default connect(mapStateToProps)(CoursePage)
I am confused with reactjs api json call back.
In my container>> i have an api response from this --> let broadcast = this.props.broadcastDetailsPageApiResponse;
I need to map the values to 'broadcastData' variable to print it in component page html.(fileds like 'channel','description','recordedUrl',
How can i do it?
The api response as follows.
broadcastdetailcontainer.jsx: place to map console.log("need to map");line no 34.
import React, {Component} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux';
import BroadcastDetailPage from '../components/broadcastList/broadcastDetailPage.jsx'
import * as detailPageActions from '../actions/detailPageActions.jsx'
class BroadcastDetailContainer extends Component {
constructor(props) {
super(props);
this.state = {broadcastData: {}};
this.updateBroadcastData = this.updateBroadcastData.bind(this);
}
componentDidMount() {
let broadcastId = this.props.params.broadcastId;
console.log("Broadcast Id in the componentDidMount: " + broadcastId);
this.updateBroadcastData(broadcastId);
}
updateBroadcastData(broadcastId) {
let broadcastData;
let broadcast = this.props.broadcastDetailsPageApiResponse;
// console.log("broadcast: " + JSON.stringify(broadcast));
if (broadcast != null) {
/////////////////////////////////////////////////////////////////
broadcastData = broadcast.channel;
broadcastData = broadcast.user;
console.log("need to map");
//console.log(broadcastData);
/////////////////////////////////////////////////////////////////
}
let content = this.props.homePageApiResponse.content;
if (content != null & broadcastData == null) {
console.log('entered when the home API');
for (let i = 0; i < content.length; i++) {
if (content[i].id == broadcastId) {
broadcastData = content[i];
break;
}
}
}
if (broadcastData == null) {
content = this.props.searchPageApiResponse.content;
if (content != null) {
console.log('entered when the search API');
for (let i = 0; i < content.length; i++) {
if (content[i].id == broadcastId) {
broadcastData = content[i];
console.log(broadcastData);
break;
}
}
}
}
if (broadcastData == null) {
this.props.actions.callDetailApi(broadcastId);
}
else{
this.setState({broadcastData: broadcastData});
}
}
componentWillReceiveProps(nextProps) {
let broadcastId = nextProps.params.broadcastId;
console.log('componentWillReceiveProps');
this.updateBroadcastData(broadcastId);
}
render() {
//console.log("rendered: "+JSON.stringify(this.props.broadcastDetailsPageApiResponse));
return (
<div>
{this.state.broadcastData &&
<BroadcastDetailPage
broadcastDetail={this.state.broadcastData}/>
}
</div>
)
}
}
const mapStateToProps = (state) => ({
homePageApiResponse: state.homePageApiResponse,
searchPageApiResponse: state.searchPageApiResponse,
broadcastDetailsPageApiResponse: state.detailPageApiResponse,
})
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(detailPageActions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)
(BroadcastDetailContainer)
I need to display the map values in the following component page:
import React, {Component} from "React";
import {Row, Clearfix} from "react-bootstrap/lib";
import VideoPlayer from "./videoPlayer.jsx";
class BroadcastDetailPage extends Component {
render() {
let broadcastData = this.props.broadcastDetail;
return (
<Row>
<div className="popup-cont-container">
<VideoPlayer broadcastData={broadcastData}/>
<div className="video-info">
<div className="info-left">
<div className="main-tag">
# {broadcastData.channel}
</div>
<div className="datenTime">
On Date
</div>
<div className="datenTime"> Location
</div>
<div className="video-info-main"> </div>
<div className="at">#
{broadcastData.handle} </div>
</div>
<div className="info-right">
<span><img src="images/eyeico.png"/>
<a> </a> Live viewers
</span>
<span><img src="images/heart.png"/>
<a> </a> Likes
</span>
</div>
</div>
<Clearfix/>
</div>
</Row>
);
}
}
export default BroadcastDetailPage
{"id":4,"user":{"userId":1,"chatUserId":0,"handle":"satishkrypto","countryCode":"+971","phone":"569942359","picUrl":"https://ss-ap-southeast-1.amazonaws.com/production-speakerswire-images/user-profiles/male3x.png","userStat":{"id":1,"followers":4,"followings":5,"broadcastLikes":0,"broadcastViews":90},"name":"satish verma","existingUser":false,"userProfileImageType":"MALE","invitesLeft":4,"userPriviledge":"SW_BROADCASTER"},"description":"satish's Broadcast","streamId":"pub11489928734882","audio":false,"screenShotUrl":"https://ss-api-eb-dev.s3-ap-southeast-1.amazonaws.com/broadcast-images/pub11489928734882-1489928751454.jpg","recordedUrl":"https://production-ss-videos-red5pro.s3-ap-southeast-1.amazonaws.com/video/record/pub581489997130311.mp4","status":"RECORDED","type":"PUBLIC","locationEnabled":false,"commentsEnabled":true,"channel":{"channelId":14,"channel":"Productivity","color":"#4A148C","priority":986,"created":1489922543000,"updated":1489922543000,"broadcast":0,"liveBroadcast":0},"broadcastStat":{"id":4,"likes":0,"views":14,"viewers":5,"liveViewers":0},"latitude":0.0,"longitude":0.0,"startTime":1489928737000,"endTime":1489928787000,"updated":1489928737000,"event":{"id":4,"description":"satish's Broadcast","type":"BROADCAST_PUBLIC","startTime":1489928737000,"endTime":1489928787000,"status":"FINISHED","eventReminderStatus":"NOT_SENT","updatedAt":1489928787000},"expectedDuration":0,"serviceProvider":"agora"}
Update:
broadcastData = {
...broadcast,
broadcaster: {
name: broadcast.user.name,
handle: broadcast.user.handle
},
channel: {
// channelName: broadcast.channel
},
likes: broadcast.broadcastStat.likes,
views: broadcast.broadcastStat.views,
}
Component 1
render() {
return (
<div className="flexslider tabs_slider no-slide">
<ul className="slides">
{this.state.Movies.map((item, index) => <Component2
key={item.db_recom_id}
item={item}
/>)}
</ul>
</div>
)
}
Component 2
render() {
return (
<li>
<img className="wrap_me" src={this.props.item.db_movies_img} />
)
}
Values that you specified in ques, are present directly inside object, you can access them by data.channel.any_key, data.description, data.recordedUrl.
If you want to print all the values of data.channel, then use map otherwise you can access directly by data.channel.channel.
Check this example:
let data = {
"id":4,
"user":{
"userId":1,
"chatUserId":0,
"handle":"satishkrypto",
"countryCode":"+971",
"phone":"569942359",
"picUrl":"https://ss-ap-southeast-1.amazonaws.com/production-speakerswire-images/user-profiles/male3x.png",
"userStat":{
"id":1,
"followers":4,
"followings":5,
"broadcastLikes":0,
"broadcastViews":90
},
"name":"satish verma",
"existingUser":false,
"userProfileImageType":"MALE",
"invitesLeft":4,
"userPriviledge":"SW_BROADCASTER"
},
"description":"satish's Broadcast",
"streamId":"pub11489928734882",
"audio":false,
"screenShotUrl":"https://ss-api-eb-dev.s3-ap-southeast-1.amazonaws.com/broadcast-images/pub11489928734882-1489928751454.jpg",
"recordedUrl":"https://production-ss-videos-red5pro.s3-ap-southeast-1.amazonaws.com/video/record/pub581489997130311.mp4",
"status":"RECORDED",
"type":"PUBLIC",
"locationEnabled":false,
"commentsEnabled":true,
"channel":{
"channelId":14,
"channel":"Productivity",
"color":"#4A148C",
"priority":986,
"created":1489922543000,
"updated":1489922543000,
"broadcast":0,"liveBroadcast":0
},
"broadcastStat":{
"id":4,
"likes":0,
"views":14,
"viewers":5,
"liveViewers":0
},
"latitude":0.0,
"longitude":0.0,
"startTime":1489928737000,
"endTime":1489928787000,
"updated":1489928737000,
"event":{
"id":4,
"description":"satish's Broadcast",
"type":"BROADCAST_PUBLIC",
"startTime":1489928737000,
"endTime":1489928787000,
"status":"FINISHED",
"eventReminderStatus":"NOT_SENT",
"updatedAt":1489928787000
},
"expectedDuration":0,
"serviceProvider":"agora"
};
class App extends React.Component{
render(){
return(
<div>
Channel Details: {Object.keys(data.channel).map(el=>{
return <p>{el}: {data.channel[el]}</p>
})}
Description: {data.description}
RecordedUrl: {data.recordedUrl}
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
I have a simple Cart component and I want to show either a "Your cart is empty" message when there are no items in it.
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as CartActions from '../actions/cart'
import Shelf from './Shelf'
import EmptyCart from './EmptyCart'
/*
This is a container component
*/
class Cart extends Component {
constructor(props) {
super(props)
this.state = {
itemQuantity: props.cart.length
}
}
render() {
const CartItems = this.props.cart.map(
(item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
)
const isCartEmpty = () => this.state.itemQuantity === 0
console.log("is cart empty? ", isCartEmpty(), "cart item quantity ", this.state.itemQuantity)
return(
<div className="Cart">
<Shelf addItem={this.props.action.addToCart} />
<h2>Cart Items</h2>
<ol>
{ isCartEmpty() ? <EmptyCart/> : {CartItems} }
</ol>
</div>
)
}
}
function mapStateToProps(state, prop) {
return {
cart: state.cart
}
}
function mapDispatchToProps(dispatch) {
return {
action: bindActionCreators(CartActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Cart)
My Shelf component looks like this:
import React, { Component } from 'react';
class Shelf extends Component {
constructor(props) {
super(props)
this.addItemToCart = this.addItemToCart.bind(this)
this.state = {
shelfItems: [
{ "name": 'shampoo', "price": 23 },
{ "name": 'chocolate', "price": 15 },
{ "name": 'yogurt', "price": 10 }
]
}
}
addItemToCart(item){
this.props.addItem(item)
}
render() {
const shelfItems = this.state.shelfItems.map((item, idx) => {
return <li key={idx}><button onClick={()=>this.addItemToCart(item)}>[+]</button>{item.name} - ${item.price}</li>
})
return(
<div>
<h2>Shelf</h2>
<ul>
{shelfItems}
</ul>
</div>
)
}
}
export default Shelf
Cart Reducer:
export default(state = [], payload) => {
switch (payload.type) {
case 'add':
return [...state, payload.item]
default:
return state
}
}
addToCart action:
export const addToCart = (item) => {
return {
type: 'add',
item
}
}
The empty message shows up but the list does not update when I add items. What am I doing wrong? The code works just fine if I remove the conditionals and just render CartItems
It's because you set only initial state. When you add item you don't set a new state. If you use redux there is no local state needed.
Try this:
class Cart extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
const CartItems = this.props.cart.map(
(item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
)
const isCartEmpty = CartItems.length === 0
return(
<div className="Cart">
<Shelf addItem={this.props.action.addToCart} />
<h2>Cart Items</h2>
<ol>
{isCartEmpty ? <li>Your Cart is Empty</li> : CartItems}
</ol>
</div>
)
}
}
My handleTeamChange function is erroring and coming back as undefined when the renderTeamMethod runs. I tried passing the variable team into on like "this.handleTeamChange.bind(this, team)" as well but nothing. I've tried a ton of different ways to call teh handleTeamChange method but so far nothing but undefined. Any thoughts?
import React, { Component } from 'react';
import UserDropdown from './user-dropdown';
import { getTeams } from 'api/index.js';
let teams = [];
let selectedTeamID = null;
let selectedTeamName = 'all_teams';
let teamId = '';
export default class TopNav extends Component {
constructor(props, context) {
super(props, context);
// this.handleTeamChange = this.handleTeamChange.bind(this);
this.state = {
teams: [],
team: {},
selectedTeamID: null,
selectedTeamName: 'All Teams',
teamSelection: false
};
}
handleClick() {
this.setState({
teamSelection: true
});
}
componentWillMount() {
getTeams().then((response) => {
teams = response.data;
this.setState({teams: teams});
});
}
renderTeams() {
return teams.map(function(team) {
if (team.active === true) {
return (
<div
onClick={ () => { this.handleTeamChange(team) } }
className="team-filter-team"
key={team.id}
value={team.id} >{team.TeamName}
</div>
);
}
});
}
handleTeamChange(team) {
console.log(team);
}
render () {
return (
<nav className="nav-wrapper">
<img className="logo-medium nav-logo" src={"https://s3-us-west-2.amazonaws.com/mvtrak/MVTRAKbrandmark.png"} />
<div onClick={ this.handleClick.bind(this) } className="team-selected"> { this.state.selectedTeamName } </div>
<div className="team-filter-container">
{this.renderTeams()}
</div>
<UserDropdown />
</nav>
);
}
}
the function body where you're mapping teams is not bound to the component's scope, therefore this is undefined.
change teams.map(function (team) { ... }) to e.g. a fat arrow teams.map((team) => ... ):
return teams.filter(team => team.active).map((team) => (
<div
onClick={ () => { this.handleTeamChange(team) } }
className="team-filter-team"
key={team.id}
value={team.id}
>
{team.TeamName}
</div>
))