This is surely really easy but I didn't find the solution.. I want to use the delete button but I'm getting an error. Thanks in advance guys.
This is the code where props call the properties of a Toy class parent, I want to delete by Id using MongoDB:
import React, { useContext } from 'react';
import UserContext from '../../context/UserContext';
import Axios from 'axios';
export default function AdminOptions(props) {
const { userData } = useContext(UserContext);
console.log(props.value._id)
//I tried this log and it gives me the id of the toy
deleteToy = async(id) => {
await Axios.delete('api/toys/delete' + id);
alert('Toy deleted');
}
return (
<div>
{userData.user ? (
<>
<br/>
<button className="btn btn-danger" onClick={this.deleteToy(props.value._id)}>
Delete toy
</button>
</>
) : (
<>
</>
)}
</div>
)
}
And this is the error I get
Failed to compile.
Line 15:5: 'deleteToy' is not defined no-undef
You are using the variable deleteToy without defining it (with either const, let or var), hence the error.
You are referring to this.deleteToy, yet your variable is just deleteToy.
In your event handler, you are not passing a function reference but actually calling the function right away. You can prepend () => to fix it (passing an arrow function that then calls yours when called). (Thanks, Emre Koc, I missed that.)
The fixed code would look like this:
import React, { useContext } from 'react';
import UserContext from '../../context/UserContext';
import Axios from 'axios';
export default function AdminOptions(props) {
const { userData } = useContext(UserContext);
console.log(props.value._id)
//I tried this log and it gives me the id of the toy
const deleteToy = async(id) => {
await Axios.delete('api/toys/delete' + id);
alert('Toy deleted');
}
return (
<div>
{userData.user ? (
<>
<br/>
<button className="btn btn-danger" onClick={() => deleteToy(props.value._id)}>
Delete toy
</button>
</>
) : null}
</div>
)
}
Add const before deleteToy . It will work
Related
I try use Notistack in my project but I have a little problem. I installed tthis library and I try use that in the basic version:
import { SnackbarProvider, enqueueSnackbar } from 'notistack'
const App = () => {
return (
<div>
<SnackbarProvider />
<button onClick={() => enqueueSnackbar('That was easy!')}>Show snackbar</button>
</div>
)
}
But it display error:
Uncaught (in promise) SyntaxError: The requested module '/node_modules/.vite/deps/notistack.js?t=1664307735906&v=92d18e2e' does not provide an export named 'enqueueSnackbar'
After I remove importing enqueueSnackbar and onClick from button, app runing but this feature doesn't work, of course. I tryed other option: second code from docs and here I used useSnackbar (I know this code is different but I show only this frament which generate the error):
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
Effect is very similar - enqueueSnackbar is undefined. How can I use this library? I don't know that this is important but I use Laravel + Breeze + #mui.
You need to wrap all parent component to SnackbarProvider component.
import { SnackbarProvider, enqueueSnackbar } from 'notistack'
const App = () => {
return (
<SnackbarProvider>
<div>
<button onClick={() => enqueueSnackbar('That was easy!')}>Show snackbar</button>
</div>
</SnackbarProvider>
)
}
I created a react component with rendering call details, in component I use useEffect to set the callInfo state, then it caused infinite loop, even I use [] as second parameter, can anyone help me fix this, thanks!
import { useLocation } from "react-router-dom";
import { useState, useEffect } from "react";
const ActivityDetail = ({ onToggleArchived }) => {
const { call } = useLocation().state;
const [callInfo, setCallInfo] = useState(null);
console.log({...call});
useEffect(() => {
setCallInfo({ ...call });
}, [])
return (
<div>
<h3 className="title">Call Details</h3>
<hr />
{
callInfo && <div>
<p>From: {callInfo.from}</p>
<p>To: {callInfo.to}</p>
<p>Time: {callInfo.created_at}</p>
<button onClick={onToggleArchived(callInfo.id)}>
{callInfo.is_archived ? "Unarchive" : "Archive"}
</button>
</div>
}
</div>
)
}
export default ActivityDetail
This is error information:
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
The problem lies within your return:
<button onClick={onToggleArchived(callInfo.id)}>
{callInfo.is_archived ? "Unarchive" : "Archive"}
</button>
Here, you are calling the function onToggleArchived which presumably (it's not in the code you posted) does state updates.
how to fix it:
wrap it in an arrow function
<button onClick={()=>onToggleArchived(callInfo.id)}>
{callInfo.is_archived ? "Unarchive" : "Archive"}
</button>
EDIT: In addition to the original answer about misusing state (which you need to correct), I missed the point that you were calling the function instead of wrapping it:
<button onClick={() => onToggleArchived(callInfo.id)}>
// instead of
<button onClick={onToggleArchived(callInfo.id)}>
ORIGINAL ANSWER
in component I use useEffect to set the callInfo state
But this is a problem because call is not component state - it's coming from useLocation(). Just let it come from there and remove the component state stuff altogether.
i.e. treat it as if it were a prop.
import { useLocation } from "react-router-dom";
import { useState, useEffect } from "react";
const ActivityDetail = ({ onToggleArchived }) => {
const { call: callInfo } = useLocation().state;
return (
<div>
<h3 className="title">Call Details</h3>
<hr />
{
callInfo && <div>
<p>From: {callInfo.from}</p>
<p>To: {callInfo.to}</p>
<p>Time: {callInfo.created_at}</p>
<button onClick={() => onToggleArchived(callInfo.id)}>
{callInfo.is_archived ? "Unarchive" : "Archive"}
</button>
</div>
}
</div>
)
}
export default ActivityDetail
If the terms used in question are incorrect please bare with me as this is the first time i'm using react js. I have written some code by referring lot of blogs, youtube, docs etc. and now i'm stuck since it is a mix of everything.
I have a requirement where i make a get call to an endpoint (about.js component) which returns json data which will be passed to (workspace.js component) where it is rendered and displayed. so far it is working fine.
next step, there is a link 'delete'(in cards element of workspace.js) on clicking, it should make a post call to an endpoint with the project_name. here i'm unable to make it work (confused with const, functions etc).
below is the code : (about.js)
import React, { useState, useEffect } from "react";
import Card from "react-bootstrap/Card";
import "./About.css";
import axios from "axios";
import Account from "./Workspace";
function About() {
const [resp_data, setdata] = useState("");
useEffect(() => {
const axios = require("axios");
axios({
method: "get",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
url: "http://127.0.0.1:8000/api/projects/",
})
.then(function (response) {
setdata(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {});
}, []);
if (resp_data != "") {
return (
<div>
<Account user={resp_data} />
</div>
);
} else {
return <h2>Loading...</h2>;
}
}
export default About;
workspace.js
import React, { Component } from "react";
import Card from "react-bootstrap/Card";
const Account = (props) => {
function handleClick(event) {
alert(event);
//need to get the project_name here
//make post call to an endpoint with project_name as data
}
const users = props.user.data;
return (
<div>
{users.map((user) => (
<div className="card-rows">
<Card className="card" key={user.Id}>
<Card.Body>
<Card.Title>
<b>Project : </b>
{user.project_name}
</Card.Title>
<Card.Subtitle className="mb-2 text-muted">
<b>DataSet : </b>
{user.dataset_name}
</Card.Subtitle>
<Card.Subtitle className="mb-2 text-muted">
<b>DataType : </b>
{user.data_type}
</Card.Subtitle>
<Card.Link
href="#"
name="hello"
className="delete"
onClick={this.handleClick({user.project_name})} // call handleclick and the projectname should be available within the function
>
Delete
</Card.Link>
<Card.Link href="/launch" className="launch">
Launch
</Card.Link>
</Card.Body>
</Card>
</div>
))}
</div>
);
};
export default Account;
it would be a great assistance if anyone could help
If you are in an functional component, you can get the user prop by adding curl braces. Also modify your onClick.
React onClick Event Handling
I would recommend you to go through React Documentation thoroughly if starting out.
This should work for you.
const Account = ({user}) => {
//use curly braces around props to fetch user prop
function handleClick(project_name) {
alert(project_name);
//need to get the project_name here
//make post call to an endpoint with project_name as data
}
return(
... //above code
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() => handleClick(user.project_name)}
>
Delete
</Card.Link>
... //below
)
I believe the issue is how you are handing the onClick function in the Card.Link component.
OnClick functions take a function to handle the event. So right now you are just invoking a function but that wouldnt have any effect on the event that is implicitly being passed into the component.
More can be found here: https://reactjs.org/docs/handling-events.html
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() => this.handleClick({user.project_name})} />
The problem in your implementation lies here
onClick={this.handleClick({user.project_name})}
because this would make the call while component gets rendered. But the react synthetic event handlers expect a function reference to be passed.
In order to achieve the same You can simply convert the onClick handler for Delete button
from
onClick={this.handleClick({user.project_name})}
to
onClick={() => this.handleClick(user.project_name)}
That would look like below
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() =>
this.handleClick(user.project_name)}>
Delete
</Card.Link>
So, directly the handleClick method would receive the project_name.
const handleClick = project_name => {
console.log(projectName);
//You can use `project_name ` for making the API call.
}
Sorry, I'm kinda new to react ,why I'm not being able to map through the data.
I have tried a different couple of things but nothing has helped.
Maybe the reason is that it's an object.
Can any one help?
import React, { Component } from "react";
import axios from "axios";
import "./Profile.css";
import ProfileCard from "../ProfileCard/ProfileCard";
class Profile extends Component {
state = {
userInfo: {}
};
componentDidMount() {
const { id } = this.props.match.params;
axios
.get(`/api/user/info/${id}`)
.then(
response => this.setState({ userInfo: { ...response.data, id } }),
() => console.log(this.state.userInfo)
);
}
render() {
let userInfoList= this.state.userInfo.map((elem,i)=>{
return(
<div> name={elem.name}
id={elem.id}</div>
)
})
console.log(this.state.userInfo);
return (
<div>
{/* <p>{this.state.userInfo}</p> */}
{/* <div >{userInfoList}</div>
<ProfileCard profilePic={this.state.userInfo} /> */}
</div>
);
}
}
export default Profile;
I think I understand what youre trying to do.
First you should change userInfo to an empty array instead of an empty object as others have stated.
Next since you are making an async api call you should use a ternary expression in your render method, because currently React will just render the empty object without waiting for the api call to complete. I would get rid of the userInfoList variable and refactor your code to the following:
RenderProfile = (props) => (
<div>
{props.elem.name}
</div>
)
{ this.state.userInfo
? this.state.userInfo.map(elem => < this.RenderProfile id={elem.id} elem={elem} /> )
: null
}
Let me know if it worked for you.
I am creating a todo List application using reactJS. If I write two different logic in two separate files it works just fine but while combining those two files it gives an error.
RenderRemaining.js file:
import React from 'react';
import { connect } from 'react-redux';
import store from '../store/store';
import RenderRemainingData from './RenderRemainingData';
const RenderRemaining = (props) => {
return (
<div>
<h2>Tasks: </h2>
<hr />
{props.list.map((detail) => {
return <RenderRemainingData key={detail.id} {...detail} />
})}
</div>
);
}
const mapStateToProps = (state) => {
return {
list: state.todoReducer
};
}
export default connect(mapStateToProps)(RenderRemaining);
RenderRemainingData.js file:
import React from 'react';
import { connect } from 'react-redux';
import removeTodo from '../actions/removeTodo';
const RenderRemainingData = ({ dispatch, todo, id, description, isCompleted }) => {
if (!isCompleted) {
return (
<div key={id}>
<h4>{todo}
<span className="float-right">
<a href="#" title="Remove" onClick={() => {
dispatch(removeTodo({todo, description, id}));
}}><i className="fas fa-times"></i></a>
</span>
</h4>
<p>{description}</p>
</div>
);
}
return false;
}
export default connect()(RenderRemainingData);
Now above code works just fine.
After combining above two files as one js file in RenderRemaining.js and deleting RenderRemainingData.js file.
RenderRemaining.js file: (after combining)
import React from 'react';
import { connect } from 'react-redux';
import store from '../store/store';
import removeTodo from '../actions/removeTodo';
const RenderRemainingData = ({ dispatch, todo, id, description, isCompleted }) => {
if (!isCompleted) {
return (
<div key={id}>
<h4>{todo}
<span className="float-right">
<a href="#" title="Remove" onClick={() => {
dispatch(removeTodo({todo, description, id}));
}}><i className="fas fa-times"></i></a>
</span>
</h4>
<p>{description}</p>
</div>
);
}
return false;
}
const RenderRemaining = (props) => {
return (
<div>
<h2>Tasks: </h2>
<hr />
{props.list.map((detail) => {
return <RenderRemainingData key={detail.id} {...detail} />
})}
</div>
);
}
const mapStateToProps = (state) => {
return {
list: state.todoReducer
};
}
connect()(RenderRemainingData);
export default connect(mapStateToProps)(RenderRemaining);
Now when an event of onClick occurs it gives an error as dispatch is not a function in console.
I don't know why is this happening.
This is because when you are rendering the RenderRemainingData component inside RenderRemaining you are not passing the dispatch, but in case of separate file, component will receive the dispatch from connect.
Possible Solutions:
1- Pass the dispatch in props to RenderRemainingData component:
return <RenderRemainingData key={detail.id} {...detail} dispatch={props.dispatch} />
And remove this line:
connect()(RenderRemainingData);
2- Another possible solution is:
Use a wrapper component and instead of rendering RenderRemainingData render that Wrapper component. Like this:
const WrapperRenderRemainingData = connect()(RenderRemainingData);
return <WrapperRenderRemainingData key={detail.id} {...detail} />
Calling connect()(SomeRandomComponent) means you are calling a function which will return you a value, a new Component that you can use.
So in the case of two separate files, first you create a new Component with connect()(RenderRemainingData), then you export the return value.
These two are equivalent.
export default connect()(SomeRandomComponent)
and
const newComponent = connect()(SomeRandomComponent)
export default newComponent
Now, if we look at bottom of your file containing the combined code.
connect()(RenderRemainingData);
export default connect(mapStateToProps)(RenderRemaining);
First expression, creates a newComponent by wrapping connect around RenderRemainingData. But since you didn't assign the return value to a new identifier or RenderRemainingData( you can't because latter is a const , by the way). Also, when you pass a function as a parameter, it is passed by value, so altering the parameter function inside the calling function will not affect its usage outside the calling function.
Easiest Solution for you will be the one mentioned below.
const RenderRemainingData = connect()(props => {
///Add the implementation here
})
There you go, you have a connected component in the same file, with dispatch available.