Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have problem with passing id to every depending on id.
I have a list of components (with different props) and need to add interaction to every component, which link to that page depends on id.
export const ResultItem = (id) =>
<div>
<Link to={{
pathname: `/idea/${id}`,
}}><button>View Recipe</button></Link>
</div>
;
Later in child component i need access to this id for make an API CALL to endpoint, with specific id to get data and render them.
class Component extends Component{
componentDidMount() {
// how can i declare variable depends on id here (i have id in url too
axios
fetch('http://localhost:50647/fund/GetFund/{id}')
(API CALL LOGIC)
}
render(){
return(
<div>
</div>
)
}
};
How can I pass id to child component via Link and declare it as variable to make an API CALL depends on id?
You can get the id like this inside your page component:
this.props.match.params.id
With your code using withRouter(component)
componentDidMount() {
axios.fetch('http://localhost:50647/fund/GetFund/{this.props.match.params.id}')
}
If you are using react-router, you can use:
this.props.match.params.id
To access a path variable (path param).
Be careful that you should use withRouter HOC to have access to routing information in props.
export default withRouter(MyComponent);
If the other answers don't work for you, maybe you can try:
const linkCustomProps = { id: 4 };
const toObject = { pathname: "/", customProps: linkCustomProps };
<Link to={toObject}>Click me</Link>;
Then you can access the value by:
this.props.location.customProps.id
BTW I'm using client-side HashRouting in my specific situation.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
I have a component which called <Header> and another component <AboutMe>, I wanted to pick an element with an id from <AboutMe> and add an event listener onClick.
the thing is whenever i try to use getElementById it returns the element which I wanted but when I try to add the event listener...throws an error.
Related to your title of this question:
You can achieve the passing of data and objects through to child components through the use of attributes where you use your component.
You really don't need to use the DOM to access the elements on the page, and with React being highly dynamic in nature, the DOM is in a constant state of change which can lead to many issues if you try to bypass React.
So if you have your header component used in your app like this...
<PageHeader userData={ userData } />
Then within your component, which is named PageHeader in this example, define the constants as:
const PageHeader = (props) => {
const userData= props.userData;
Note the object name to use with "props" is the same that you used with the attribute name.
Props will contain all attributes that are defined on the attribute where the component is used.
Just to provide another way to use "props" (the name is not significant) I'll include this code snippet too. Notice that react will auto map each one to it's proper constant... which is pretty cool.
const PageHeader = ( props ) => {
const { uischema, schema, path, visible, renderers, userData } = props;
And one last thing that I should mention, is the use of the props.children, which can be very useful too. This is where DivScrollable is defined, and is using the props.children.
const DivScrollable = (props) => {
return (
<div className={styles.divscrollable} >
{props.children}
</div>
);
};
So the power of props.children is that it passes along the contents of what is contained between the opening and closing tags of a component. In this example it's the MyComponent object that is within the props.children object. But it could also include others too since it's "all of the content" between the component tags.
<DivScrollable>
<MyComponent src={props.src}
theme="monotyped"
spacing="4"
enableClipboard="true"
name={null}
/>
</DivScrollable>
To then address the onClick handling, which you mention within the body of your question, you can use use it like the following, where I am reusing the above examples... see the "onClick" addition within the DivScrollable component.
const DivScrollable = (props) => {
const performSomeFunction= (aValue) => {
... code goes here...;
};
return (
<div className={styles.divscrollable}
onClick={() => {
performSomeFunction(true);
}} >
{props.children}
</div>
);
};
I am not sure why you mentioned Header component, but did you try like this?
function clickEvent() {
...
}
const el = document.getElementById("element_id");
el.addEventListener("click", clickEvent, false);
how do I call a function of a child component in the parent component when using setState with a callback function?
Background information
Three components of a simple quiz app:
App.jsx
-- Questions.jsx
-- Results.jsx
To access the answers in the results component AND the questions component, the answers must be saved in the state of the app component.
To modify the state of the app component, each time the user answers a question, I need to call a function that is passed down from the app component to the questions component. After setting the State of the app component, the next question should be displayed. Hence, the function nextQuestion() in the questions component should be called. Normally, I would just write setState({results: results}, nextQuestion()) but since nextQuestion() is a function of the questions component and not of the app component, this does not work.
How can I solve this problem?
Thank you very much!
In the questions component:
checkAnswer = (answer) => {
if (answer !== this.state.solution) {
let s = this.state;
this.props.saveResult(s.question, s.solution[0], answer);
//[...]
}
};
newQuestion = () => {
//[...]
let question = [...this.state.question];
let solution = [...this.state.solution];
const task = taskGenerator.taskDirectory[taskId](); //generate new question + solution
question = task.question;
solution = task.solution;
this.setState({ question, solution });
};
In the app component:
saveResult = (question, solution, answer) => {
let results = cloneDeep(this.state.results)
results.question = question
results.solution = solution
results.answer = answer
this.setState({ results: results }, newQuestion()); //here is the problem; how do I call the newQuestion function of the child component?
};
how do I call a function of a child component in the parent component when using setState with a callback function?
In short, you don't :) Instead, you pass the state from the parent to the child. That's actually the root of your problem with:
but since nextQuestion() is a function of the questions component and not of the app component, this does not work.
In short, there are two "rules" to follow as a React dev for where your state needs to go in your app. To understand them, you have to think of your app as a "tree", with App at the top and all children components, grandchildren components, etc. below ...
The state must be at or above every component that needs to use the state
The state should be as low as possible in your app tree (while still following #1)
It seems you are trying to follow rule #2 and keep your state low (good) ... but your app is breaking that first rule: you have state (nextQuestion relies on this.state.question) which your App depends on. That state is "lower" (in your app tree) than it needs to be, and since it's not at the App-level, App can't use it.
What this means is that you need to move nextQuestion (and the state(s) powering it) into App, so that your code in App can access nextQuestion. Then, you can pass any data that Question needs as props, from App.
With this structure your state (and associated functions like nextQuestion) will live as high as it needs to live (ie. at the App-level), so that all logic that relies on it has access, and any "lower" components (like Question) will simply have that state passed "down the tree" via props.
class App extends Component {
...
setAnswers(answers, callback){
this.setState({results:answers},callback)
}
render(){
return <Questions setAnswers={this.setAnswers}/>
}
}
class Questions extends Component {
onSubmit(answers){
this.props.setAnswers(answers,this.nextQuestion)
}
}
another way would be to react to state change in Questions child component, probably the better way.
If I understand your problem correctly, you should be able to pass the function as props to the child component from the parent. I believe this post answers your question as well.
Call child method from parent
Cheers!
This question already has answers here:
How to get previous url in react gatsby
(4 answers)
Closed 2 years ago.
Is there any way to find the path of the page that a user is on on a Gatsby site and store it in a const so that it can be checked next to the current path the user is on? In other words if they're on the /about page, and are clicking a link to navigate to the /contact page, I need to get the paths of both so that I can check them against each other. I know I can get location.pathname for the current url, but how do I find the path that they are navigating to when the click a link?
Since your code structure isn't clear. Assuming a simple anchor tag, you can do something like this:-
<a href="/new/link" onClick={getHref}>New Link</a>
And in your getHref method
function getHref(event){
console.log(event.target.href); // should log '/new/link'
}
Check if this works in your case.
Please forgive for any typo, I havent validated it.
Gatsby exposes props (because it extends from #reach/router from React) by default on the top-level components (this means pages). You can pass it to the child components as you wish or store it in a const or in a React's state.
Without knowing any page structure, I'll provide something dummy as an example:
import React from "react"
import { graphql } from "gatsby"
const YourPage = ({ location, data }) => {
console.log('your page is ', location.pathname)
return <div>Dummy content</div>
}
export default Page
export const query = graphql`
query PageQuery {
site {
siteMetadata {
siteURL
}
}
}
`
Your information is stored under props.location, that's why you can destructure it in the component's declaration.
In the case above, I've used pathname property but you have a bunch exposed. Check it out to find out which one fits your requirements.
I have setup gatsby project using this link. It is working correctly.
Now I know how to create route by defining the component inside the pages folder. But now I have a new challenge I need to create one dynamic route so that I can pass my id in it (Just like reactjs).
<Route path: "/path/:id"/>
How do I do that in gatsby?
You have to explicitly tell gatsby that a path should be dynamic. From the docs:
// gatsby-node.js
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/app/)) {
page.matchPath = "/app/*"
// Update the page.
createPage(page)
}
}
and then you can use dynamic routing in src/pages/app.js
import { Router } from "#reach/router"
const SomeSubPage = props => {
return <div>Hi from SubPage with id: {props.id}</div>
}
const App = () => (
<Layout>
<Link to="/app/1">First item</Link>{" "}
<Link to="/app/2">Second item</Link>{" "}
<Router>
// ...dynamic routes here
<SomeSubPage path="/app/:id" />
</Router>
</Layout>
)
export default App
Everything that goes to /app/* will be handled dynamically now. You should find your id as usual in the props.
Have a look at their authentication example https://github.com/gatsbyjs/gatsby/tree/master/examples/simple-auth
You can use square brackets ([ ]) in the file path to mark any dynamic segments of the URL. For example, in order to edit a user, you might want a route like /user/:id to fetch the data for whatever id is passed into the URL.
src/pages/users/[id].js will generate a route like /users/:id
src/pages/users/[id]/group/[groupId].js will generate a route like /users/:id/group/:groupId
Reference: https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api#creating-client-only-routes
You can use gatsby-plugin-create-client-paths. It uses matchPath. For more info check
https://www.gatsbyjs.org/docs/gatsby-internals-terminology/#matchpath
https://www.gatsbyjs.org/packages/gatsby-plugin-create-client-paths/
This answer is Super late, but for anyone in the future who is faced with this problem, I have a simpler solution.
In Gatsby terms it's called a Splat Route.
For examples, If you want some page "domain.com/profile/[id]", where id can be any number, which will be used to display different data inside the website, you should name your page as [...id].
Now inside the page you can access this id as
const ProfilePage = (props) => <div>This page is for id number {props.params.id}</div>
Note: Don't miss the 3 dots, that is what signifies a splat route in gatsby.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
So I feel like there is something small here that im missing, but don't really know what.
constructor(props) {
super();
this.state = {
developers: [],
};
}
componentDidMount() {
fetch('API').then(features => {
return features.json();
}).then(data => {
let developers = data.features.map((info) => {
let developer_info = info.properties.name
return(
<div key={info.id}>
{info.properties.name}
{info.properties.skills}
</div>
)
})
this.setState({ developers: developers});
console.log("state", this.state.developers)
console.log(this.props)
})
}
I would ideally like to call
this.state.developers.name
or this.state.developers.skills
as i need this information, but currently i am only able to save one property in the this.state or i can call out each thing. as i have done above, but its not useful, bc i can't put the info where i need it.
what am i doing wrong?
As a rule of thumb, in state you only want to store "serialisable" data. In general this means you should not store functions or recursive data structures.
A good way to check if your data is serialisable is to think if you could (or attempt to) use JSON.stringify() on it.
What you are storing here is almost certainly not serialisable, as you are storing to state complete React elements. A React element is the thing that is returned when you do <Component /> (which is the same as React.createElement(Component, ...).
So, in your case, what you should do is
let developers = data.features.map((info) => {
const developer_info = {
name: info.properties.name,
skills: info.properties.skills
}
return developer_info;
});
this.setState({ developers: developers});
So now you would have an array of plain Javascript objects in your state.
Access the updated state in callback of setState:
this.setState({ developers }, () => console.log("state", this.state.developers));
You should also store the data in state instead of the component view code (the html tags).
Access this.state.developers's properties in the component view code instead.