I have 4 divs that onClick call a function. When the particular div is clicked, I want the other divs to be non-clickable. But until the particular div is clicked, I want them to be clickable. My code:
import React, { Component } from 'react';
class MyApp extends Component {
state = {
div:2
}
handleClick = (id) => {
id==this.state.div?
//disable onClick for all divs :
//do nothing
}
render() {
return (
<div>
<div onClick={()=>this.handleClick(1)}>
1
</div>
<div onClick={()=>this.handleClick(2)}>
2
</div>
<div onClick={()=>this.handleClick(3)}>
3
</div>
<div onClick={()=>this.handleClick(4)}>
4
</div>
</div>
);
}
}
export default MyApp
How do I do this? Am I correct in disabling the click from the handleClick function?
Thanks.
This is another approach I made and I hope it makes sense and helps. let me know if you have any questions
class App extends Component {
constructor(props) {
super(props);
this.state = {
buttonClick: 2,
buttons: [1,2,3,4],
clicked: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(id){
console.log('clicked ', id)
this.setState({
buttonClick: id,
clicked: true
})
}
renderInitButtons() {
const {buttons} = this.state;
return buttons.map(button => {
return <div onClick={() => this.handleClick(button)}> {button} </div>
})
}
renderButtonClicked() {
const {buttons, buttonClick} = this.state;
return buttons.map(button => {
if(buttonClick === button) {
return <div onClick={() => this.handleClick(button)}> {button} </div>
}
return <div > {button} </div>
})
}
render() {
const {buttons, buttonClick, clicked} = this.state;
return (
<div>
{
clicked? this.renderButtonClicked(): this.renderInitButtons()
}
</div>
)
}
}
render(<App />, document.getElementById('root'));
While this is more of a semantic argument, you are still firing an event in each div, regardless of its state. You're just deciding whether or not any action should be taken. If you want to make it truly have no behavior, then you have to dynamically add/remove them. The easiest way is to iterate and create the 4 divs, with a conditional to see if an onClick listener should be added
buildDivs() {
return [1,2,3,4].map(id => {
const divProps = {}
if (this.state.div === id) {
divProps.onClick = () => this.handleClick(id)
}
return <div {...divProps} key={id}>{id}</div>
}
}
render() {
return (
<div>
{this.buildDivs}
</div>
)
}
You can add locked to your state and set it to true when you want to lock other divs and return from your function if its true
I would also change the handleClick function to return a new function to keep the code more readable
class MyApp extends Component {
state = {
div: 2,
locked: false
};
handleClick = id => () => {
if (this.state.locked) return;
if (id === this.state.div) {
this.setState({ locked: true });
}
};
render() {
return (
<div>
<div onClick={this.handleClick(1)}>1</div>
<div onClick={this.handleClick(2)}>2</div>
<div onClick={this.handleClick(3)}>3</div>
<div onClick={this.handleClick(4)}>4</div>
</div>
);
}
}
If you don't want to register any handler you can also check if this.state.locked is true and return null to the onClick function
class MyApp extends Component {
state = {
div: 2,
locked: false
};
handleClick = id => {
if (this.state.locked) return null;
return () => {
if (id === this.state.div) {
this.setState({ locked: true });
}
}
};
render() {
return (
<div>
<div onClick={this.handleClick(1)}>1</div>
<div onClick={this.handleClick(2)}>2</div>
<div onClick={this.handleClick(3)}>3</div>
<div onClick={this.handleClick(4)}>4</div>
</div>
);
}
}
Related
I write messaging app. When I call the passed functions from the child component, I get the following errors:
TypeError: this.props.createNewChat is not a function.
TypeError: this.props.chooseChat is not a function.
I looked through many topics, tried what I could try and nothing worked.
Will be grateful for any suggestions as I'm a beginner in coding.
Here are parts of my code:
Parent component:
class DashboardComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
chats: [],
email: null,
selectedChat: null,
chatVisible: true
}
this.createNewChat = this.createNewChat.bind(this);
this.chooseChat = this.chooseChat.bind(this);
}
render () {
return (
<main className='dashboard-cont'>
<div className='dashboard'>
<ChatListComponent
newChat={this.createNewChat}
select={this.chooseChat}>
history={this.props.history}
chats={this.state.chats}
userEmail={this.state.email}
selectedChatIndex={this.state.selectedChat}>
</ChatListComponent>
</div>
</main>
)
}
createNewChat = () => {
this.setState({
chatVisible: true,
selectedChat: null
});
}
chooseChat = async(index) => {
await this.setState({
selectedChat: index,
chatVisible: true
});
}
Child component:
class ChatListComponent extends React.Component {
constructor(props) {
super(props);
this.select = this.select.bind(this);
this.newChat = this.newChat.bind(this);
}
render () {
if(this.props.chats.length > 0) {
return (
<main className='listOfChats'>
{
this.props.chats.map((_chat, _index) => {
return (
<div key={_index}>
<div className='chatListItem'
onClick={() => this.select(_index)}
selected={this.props.selectedChatIndex === _index}>
<div className='avatar-circle'>
<h1 className='initials'>{_chat.users.filter(_user => _user = this.props.userEmail)[1].split('')[0]}</h1>
</div>
<div className='text'>
<p id='textLine1'>{_chat.users.filter(_user => _user = this.props.userEmail)[1]}</p>
<br></br>
<p>"{_chat.messages[_chat.messages.length - 1].message.slice(0, 25)}..."</p>
</div>
</div>
</div>
)
})
}
<button className='newChatButton'
onClick={this.newChat}>
New Chat</button>
</main>
);
} else {
return (
<button className='newChatButton'
onClick={this.newChat}>
New Chat</button>
);
}
}
newChat = () => {
this.props.createNewChat();
}
select = (index) => {
this.props.chooseChat(index);
}
};
export default ChatListComponent;
You are passing them as newChat and select
<ChatListComponent
newChat={this.createNewChat}
select={this.chooseChat}>
so these are the names of the properties in the ChatListComponent
You should access them as this.props.newChat and this.props.select
newChat = () => {
this.props.newChat();
}
select = (index) => {
this.props.select(index);
}
You should use
this.props.newChat instead of this.props.createNewChat &
this.props.select instead of this.props.chooseChat
because You are passing them as newChat and select
<ChatListComponent
newChat={this.createNewChat}
select={this.chooseChat}>
history={this.props.history}
chats={this.state.chats}
userEmail={this.state.email}
selectedChatIndex={this.state.selectedChat}>
</ChatListComponent>
In child component
newChat = () => {
this.props.newChat();
}
select = (index) => {
this.props.select(index);
}
You don't have such a property in your component
<ChatListComponent
newChat={this.createNewChat}
select={this.chooseChat}>
history={this.props.history}
chats={this.state.chats}
userEmail={this.state.email}
selectedChatIndex={this.state.selectedChat}>
Your property is newChat and not createNewChat
You need to change the button's onClick to call the properties' method
<button className='newChatButton'
onClick={this.props.newChat}>
New Chat</button>
</main>
and
onClick={() => this.props.select(_index)}
I have blogposts that I need to render. The first 4 are shown. When clicking on the button underneath it, two more need to show up. When the button is clicked again, two more need to show up and so on.
Unfortunately, I am not able to do so.
Here is my code:
import React from 'react';
import axios from 'axios';
import Blogpost from './Blogpost.js';
class BlogpostReader extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
blogposts: [],
};
}
componentDidMount() {
// Loading all blogposts in state
}
renderBlogpost(i) {
// Render one blogpost
}
//This function has to be replaced by one that renders extra blogposts
showAlert(){
alert("Im an alert");
}
render() {
const {error, isLoaded} = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
for (let i = 1; i < this.state.blogposts.length && i < 5; i++) {
this.state.renderedBlogposts.push(
<div key={this.state.blogposts[i].id} className="col-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 whole-blogpost">
{this.renderBlogpost(this.state.blogposts[i])}
</div>)
}
return (
<div>
<div className="row">
{this.state.renderedBlogposts}
</div>
<div className="centered-button">
<button className="styled-button" onClick={this.showAlert}>Meer laden</button>
</div>
</div>
);
}
}
}
export default BlogpostReader;
How can I show extra blogposts after clicking the button? Please help me out!
You can do something like this :
import React from 'react';
import axios from 'axios';
import Blogpost from './Blogpost.js';
class BlogpostReader extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
blogposts: [],
count:5
};
}
componentDidMount() {
// Loading all blogposts in state
if(blogposts.length<5){
this.setState({
count:blogposts.length
})
}
}
renderBlogpost(i) {
// Render one blogpost
}
renderBlogposts(){
const blogposts=[];
const count=this.state.count;
for (let i = 1; i < count; i++) {
blogposts.push(
<div key={this.state.blogposts[i].id} className="col-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 whole-blogpost">
{this.renderBlogpost(this.state.blogposts[i])}
</div>)
}
return blogposts;
}
//This function has to be replaced by one that renders extra blogposts
addMore=()=>{
let newCount=this.state.count + 2;
if(this.state.count===this.state.blogposts.length) return;
if(this.state.count+1 === this.state.blogposts.length){
newCount=this.state.count+1
}
this.setState({
count:newCount
})
}
render() {
const {error, isLoaded} = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<div className="row">
{this.renderBlogposts()}
</div>
<div className="centered-button">
<button className="styled-button" onClick={this.addMore}>Meer laden</button>
</div>
</div>
);
}
}
}
Oh no honey. In React the recommended approach is to make things as declarative as possible. Which means that instead of imperatively pushing items onto an array and then render that array you can just render a slice of the array.
I.e. try something like this
class BlogpostReader extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
blogposts: [], // this will contain all posts
postsToShow: 2, // a simple number controls how many posts are shown
};
}
componentDidMount() {
// Loading all blogposts in state
}
increasePostsShown() {
this.setState(({ postsToShow }) => {
postsToShow: postsToShow + 1;
});
}
render() {
const { error, isLoaded, blogposts, postsToShow } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
}
const postsShown = blogposts.slice(0, postsToShow); // get only the ones you want to show
return (
<div>
<div className="row">
{postsShown.map(blog => (
<div>{blog}</div> {/* or display them however you like */}
))}
</div>
<div className="centered-button">
<button className="styled-button" onClick={this.increasePostsShown}>
Meer laden
</button>
</div>
</div>
);
}
}
Is your blogpost array containing already all the blog posts? My suggestion would be that everytime the user clicks on the button, you increment a value from the state.
this.state = {
error: null,
isLoaded: false,
blogposts: [],
nbPostToDisplay: 4
};
In your loop:
for (let i = 0 /* start at 0, not 1 */; i < this.state.blogposts.length && i < nbPostToDisplay; i++) {
Some function to increment:
function incrementNbPosts() {
this.setState(prevState => return ({nbPOstsToDisplay: prevState.nbPostsToDisplay + 2});
}
Use function above in your button callback. This will trigger a re-render of your component.
IMPORTANT: do not forget to bind your functions in the construrtor or (better) use ES6 notation.
I would better keep things simple, so that button would just set new state.posts with +1 post, thus triggering render(), that in turn will render added element.
addPost = () => {
...
this.setState({
posts: [...posts, { id: posts.length + 1 }]
});
};
renderPosts = () => {
...
};
render() {
return (
<div>
<button onClick={this.addPost}>Add</button>
{this.renderPosts()}
</div>
);
}
Made a quick sandbox illustrating provided code.
https://codesandbox.io/embed/vjlp468jk7
Here's all you need. I also cleaned up your code a little bit
class BlogpostReader extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
blogposts: [],
limit: 4
};
this.showMore = this.showMore.bind(this);
this.renderBlogpost = this.renderBlogpost.bind(this);
}
componentDidMount() {
// Loading all blogposts in state
}
renderBlogpost(i) {
// Render one blogpost
}
//This function has to be replaced by one that renders extra blogposts
showMore() {
this.setState(state => ({ limit: state.limit + 2 }));
}
render() {
const { error, isLoaded, blogpost, limit } = this.state;
if (error) {
return <div>Error: {error.message}</div>);
}
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<div className="row">
{
blogposts.map((post, index) => {
if (index + 1 !== limit) {
return (
<div key={post.id} className="col-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 whole-blogpost">
{ this.renderBlogpost(post) }
</div>
);
}
})
}
</div>
<div className="centered-button">
<button className="styled-button" onClick={this.showMore}>Meer laden</button>
</div>
</div>
);
}
}
If you want to also make showMore to accept any number of posts, you can do this...
showMore(value = 2) {
this.setState(state => ({ limit: state.limit + value }));
}
Then now you can call it with any number of posts you want. If you don't specify any value, the limit will be incremented by 2.
UPDATE
Since you've mentioned that you have to start when index is 1, then you can update your blogposts.map in the render like this
{
blogposts.map((post, index) => {
if (index && index !== limit) {
// the condition above ensures that the posts at index 0, and also when index equals limit, are not returned
// the rest of the code goes here...
}
})
}
After doing that, you can set limit to 5 in the constructor if you want to show only 4 entries at first load.
The following was the working code:
class BlogpostReader extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
blogposts: [],
limit: 5,
start: 1
};
this.showMore = this.showMore.bind(this);
}
componentDidMount() {
// Loading all blogposts into state
}
renderBlogpost(i) {
// Render a single blogost
}
showMore(){
this.setState(state => ({
start: state.limit,
limit: state.limit + 2
}));
}
render() {
const {error, isLoaded, limit} = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
var startedAt = this.state.start
for (startedAt; startedAt < this.state.blogposts.length && startedAt < limit; startedAt++) {
this.state.renderedBlogposts.push(
<div key={this.state.blogposts[startedAt].id} className="col-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 whole-blogpost">
{this.renderBlogpost(this.state.blogposts[startedAt])}
</div>
)
}
return (
<div>
<div className="row">
{this.state.renderedBlogposts}
</div>
<div className="centered-button">
<button className="styled-button" onClick={this.showMore}>Meer laden</button>
</div>
</div>
);
}
}
}
I am trying to implement in toggle button feature where when clicking on button willshowtext and clicking on button again willhidetext.
When i tried implement this i am stuck at displaying the text . I used the below for showing the text
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
console.log('Click happened');
<div>HELLO</div>
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
With this i can see the console.log is created but i cant able to see the HELLO when i clicked on the button.
Am i missing anything here ?
Any help is appreciated
Thanks
You cannot return an element from an event handler and have it render like that.
You need to hide the text behind a flag and then toggle that flag.
First we create a flag in state. This defines if the toggle text should be displayed.
this.state = {
showText: false // Should the text be displayed?
};
Next we update the click handler to toggle that state flag.
this.setState((state) => ({
showText: !state.showText // Toggle showText
}))
Finally we conditionally render the toggle text. If showText is true, then render the text, if it is false do not render it.
{this.state.showText && <div>HELLO</div>}
Optional:
As pointed out by Mosè Raguzzini you do not need to bind your event handler.
this.handleClick = this.handleClick.bind(this); // This is not needed
handleClick = () => {} // because this is an arrow function
All together now:
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.state = {
showText: false // Should the text be displayed?
};
}
handleClick = () => {
console.log('Click happened');
this.setState((state) => ({
showText: !state.showText // Toggle showText
}))
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
{this.state.showText && <div>HELLO</div>}
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
You should change state on toggle.
import React, { Component } from "react";
export default class DisplayStats extends Component {
state = {
isToggled : false
}
constructor(props) {
super(props);
}
handleClick = () => {
console.log('Click happened');
this.setState({isToggled : !this.state.isToggled});
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
{(() => {
if(this.state.isToggled){
return <div>HELLO</div>
}
else{
return <div></div>
}
})()}
)
}
}
You do not need to use bind if you already use arrow functions, beside this, you have to learn how to manage state:
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.state = {
displayedText: '',
}
}
handleClick = () => {
console.log('Click happened');
this.setState({ displayedText: 'This is my text.'});
}
render() {
return (
<div className="container">
<h1>This is the stats. {this.state.displayedText}</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
To achieve this, you'll want to track state in your component to determine if the text should be displayed or not. The following code should achieve what you're after:
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
console.log('Click happened');
// When the button is clicked, the text display state is toggled
this.setState({ showText : !this.state.showText })
}
render() {
// Extract state to determine if the text should be shown
const showText = !!this.state.showText
return (
<div className="container">
{ /* Render div with text is showState is truthy /* }
{ showText && <div>HELLO</div> }
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
That is not how react and other state based frameworks work. The idea is that the view should change when the state changes and only state can cause any change in the view. What you would need to do is on click of button, change the state which in turn will cause your view to update
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
visible: false
}
}
handleClick = () => {
this.setState({visible: !this.state.visible});
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
{ this.state.visible ? <div>Hello</div> : '' }
</div>
)
}
}
import React, { Component } from 'react';
import axios from 'axios';
import DropdownMenu from './DropdownMenu';
class Navigation extends Component {
state = {
topCategory: []
}
componentDidMount() {
axios.get('http://localhost:3030/topCategory')
.then(res => {
console.log(res.data.express.catalogGroupView);
this.setState({
topCategory: res.data.express.catalogGroupView
})
})
}
render() {
const { topCategory } = this.state;
const navList = topCategory.map(navList => {
return (
<DropdownMenu>
<li key={navList.uniqueID}> <button onClick={this.showMenu}>{navList.name}</button></li>
</DropdownMenu>
)
})
return (
<div>
<ul className="header">{navList}</ul>
</div>
)
}
}
export default Navigation;
import React, { Component } from 'react';
class DropdownMenu extends Component {
constructor() {
super();
this.state = {
showMenu: false,
};
this.showMenu = this.showMenu.bind(this);
this.closeMenu = this.closeMenu.bind(this);
}
showMenu(event) {
event.preventDefault();
this.setState({ showMenu: true }, () => {
document.addEventListener('click', this.closeMenu);
});
}
closeMenu() {
this.setState({ showMenu: false }, () => {
document.removeEventListener('click', this.closeMenu);
});
}
render() {
return (
<div>
{
this.state.showMenu
? (
<div className="menu">
<button> Menu item 1 </button>
<button> Menu item 2 </button>
<button> Menu item 3 </button>
</div>
)
: (
null
)
}
</div>
);
}
}
export default DropdownMenu;
I'm new to react and have created a navigation menu in react js. On clicking on the nav items a dropdown should appear. But in my case, it's not working, mainly the dropdown part.Can someone please guide me on this. I have tried numerous methods, but it seems not to be working. If someone could some help or atleast show me, I would be very much be grateful
I see couple of issues in your code.
In Navigation component I see the onClick is this.showMenu but there is no such function bound to that component.
You might need to read and understand how state and props work.
Hope the below snippet helps.
class DropdownMenu extends React.Component {
constructor() {
super();
this.state = {
};
}
render() {
return (
<div>
{
this.props.showMenu
? (
<div className="menu">
<button> Menu item 1 </button>
<button> Menu item 2 </button>
<button> Menu item 3 </button>
</div>
)
: (
null
)
}
</div>
);
}
}
class Navigation extends React.Component {
state = {
topCategory: []
}
componentDidMount() {
this.setState({
topCategory: [{uniqueID:1000,name:'Nav Item 1'},{uniqueID:1001,name:'Nav Item 2'},{uniqueID:1002,name:'Nav Item 3'}]
})
}
render() {
const { topCategory } = this.state;
const navList = topCategory.map(navListItem => {
return (
<li key={navListItem.uniqueID}> <button onClick={(e) => (this.setState({selected:e.target.innerText}))}>{navListItem.name}</button>
<DropdownMenu showMenu={(()=>{
return this.state.selected === navListItem.name})()}/></li>
)
})
return (
<div>
<ul className="header">{navList}</ul>
</div>
)
}
}
ReactDOM.render(<Navigation />, document.querySelector("#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'/>
The parent component Dashboard holds the state for every ListItem I add to my Watchlist. Unfortunately, every time I am adding an Item, it gets added to the DB, but only shows up when I refresh the browser.
class UserDashboard extends React.Component {
state = {
data: []
}
componentWillMount() {
authService.checkAuthentication(this.props);
}
isLoggedIn = () => {
return authService.authenticated()
}
getAllCoins = () => {
//fetches from backend API
}
addWishlist = () => {
this.getAllCoins()
.then(things => {
this.setState({
data: things
})
})
console.log("CHILD WAS CLICKED")
}
componentDidMount() {
this.getAllCoins()
.then(things => {
this.setState({
data: things
})
})
}
render() {
return (
<div className="dashboard">
<h1>HI, WELCOME TO USER DASHBOARD</h1>
<SearchBar
addWishlist={this.addWishlist}
/>
<UserWatchlist
data={this.state.data}
/>
</div>
);
}
}
The User Watchlist:
class UserWatchlist extends React.Component {
constructor(props) {
super(props)
}
// componentDidUpdate(prevProps) {
// if (this.props.data !== prevProps.data) {
// console.log("CURRENT", this.props.data)
// console.log("PREVs", prevProps.data)
// }
// }
render() {
return (
<div>
<h2>These are tssssyou are watching:</h2>
<ul className="coin-watchlist">
{
this.props.data.map((coin, idx) => {
return <ListItem key={idx}
coin={coin.ticker}
price={coin.price}
/>
})
}
</ul>
</div>
)
}
}
The search Bar that shows potential Items to watch over:
class SearchBar extends React.Component {
constructor(props) {
super(props)
this.state = {
coins: [],
searchValue: ""
}
}
searchHandler = e => {
e.preventDefault()
const value = e.target.value
this.setState({
searchValue: value
});
if (value === "") {
this.setState({
coins: []
})
} else {
this.getInfo()
}
}
getInfo = () => {
// Searches the API
}
addWishlist = () => {
this.props.addWishlist();
}
render() {
const {coins, searchValue} = this.state
return (
<div className="coin-search">
<form>
<input
type="text"
className="prompt"
placeholder="Search by ticker symbol"
value={searchValue}
onChange={this.searchHandler}
/>
</form>
<ul className="search-suggestions">
{
coins.filter(searchingFor(searchValue)).map( coin =>
<Currency
coin={coin}
addWishlist={this.addWishlist}
/>
)
}
</ul>
</div>
);
}
}
And the actual Currency that gets clicked to be added:
class Currency extends React.Component {
addToWatchlist = () => {
// POST to backend DB to save
};
fetch("/api/add-coin", settings)
.catch(err => {
return err
})
}
clickHandler = () => {
this.addToWatchlist()
this.props.addWishlist()
}
render() {
return(
<div className="search-results">
<li>
<h3> { this.props.coin.currency } </h3>
<button
className="add-to-list"
onClick={this.clickHandler}
>
+ to Watchlist
</button>
</li>
</div>
)
}
}
As you can see, I am sending props down all the way down to child. When I click the button to Add to Watchlist, I see the console.log message appear, saying "CHILD WAS CLICKED". I've even tried just calling the method to fetch from backend API again.
Also, in UserWatchlist, I've tried a componentDidUpdate, but both prevProps and this.props show the very same array of data. Somewhere in the chain, my data is getting lost.
This is also my first time posting a question here, so if it can be improved, I am happy to add extra details and contribute something to this community
You probably forgot to wait for addToWatchlist to complete:
addToWatchlist = () => {
// POST to backend DB to save
return fetch("/api/add-coin", settings)
.catch(err => {
return err
})
}
clickHandler = () => {
this.addToWatchlist().then(() => {
this.props.addWishlist()
})
}