I'm currently making a profile page wherein the route /profile/displaynamehere will display a page where one of its components is a basic information page that shows the display name of the user.
The component is called BasicInfo and accepts props called displayName. Here's how it looks like:
export default function Profile() {
const router = useRouter();
const displayNameQuery = router.query.displayName;
return (
...
<BasicInfo displayName={displayNameQuery} />
...
)
}
The problem is, displayName or {displayNameQuery} in this context is undefined whenever I try to console.log it. Is there a way wherein I can pass the query parameter as props to my component?
Related
I know that you can do navigation.navigate("address", {/* params go here */ to send parameters over to another screen. But then you have to navigate there. Is there a way of sending params over without navigating?
I have a application with multiple screens. And I want to update a useState from another component by updating its params so that a button appears. But I dont want to navigate there, I just want to update it so when the user does go there the button will be there.
Like this:
const currentComponent = (navigation) {
return (
<Button onPress={navigation.updateParams("otherComponent", {shouldShowValue: true})} />
)
}
const otherComponent = (route, navigation) {
const {shouldShowValue} = route.params
const [shouldShow, setShouldShow] = useState(shouldShowValue);
return (
{shouldShow ? <Button> Yayy this button appears now <Button /> : null}
)
}
}
'''
this is just pseudo code and not at all
like the code I have written,
but its just meant as an example to get a
understanding of what I mean.
(updateParams) isnt a function that exists,
but I want something similiar like it.
Is there a way of updating the params in a
component from another component without having
to navigate there? Like with
navigate.navigate("address" {params go here})
but without the navigation part?
You can consider using useContext() hook to execute your functionality.
Using navigation library to pass param without navigating to that page is somehow misusing the navigation function.
With useContext, you can share the state(s) among components. If you want to change the value upon clicking action, you can also pass the useState hook into useContext. Alternatively, you can consider to use redux library to share state.
import { useState, createContext, useContext } from 'react';
const shareContext = createContext(null);
export default function demoUseContext() {
const [isClicked, setClicked] = useState(false);
return (
<shareContext.Provider value={{isClicked, setClicked}}>
<ComponentA />
<ComponentB />
</shareContext.Provider>
)
}
function ComponentA() {
const sharedParam = useContext(shareContext);
return (
<button onClick={() => sharedParam.setClicked(!sharedParam.isClicked)}>
click to change value
</button>
);
}
function ComponentB() {
const sharedParam = useContext(shareContext);
return (
sharedParam.isClicked && <div>it is clicked</div>
)
}
As the example above, the code pass the useState hook from parent component into context, where A is consuming the useState from context to setup isClicked via setClicked, B is consuming the value isClicked from context.
You can also manage to setup context with value not only in a hook, but a param / object / function as a callback.
For more details, please refer to https://reactjs.org/docs/hooks-reference.html#usecontext
There're multiple hooks including useContext fyi
Passing parameters to routes
There are two pieces to this:
Pass params to a route by putting them in an object as a second parameter to the navigation.navigate function: navigation.navigate('RouteName', { /* params go here */ })
Read the params in your screen component: route.params.
We recommend that the params you pass are JSON-serializable. That way, you'll be able to use state persistence and your screen components will have the right contract for implementing deep linking.
I have an arrow function in my react native application.
I am trying to pass first props to be able to navigate between my screens and at the same time I want also to pass in route because I want to pass data between my screens.
However, with the following code I have, whatever I put as the second parameter, it is always undefined... and the first one will work correctly.
Please let me know what I must do to be able to pass in two parameters:
const Home = ({route, props}) => {
{console.log(route.params.id)}
{console.log(props)}
}
I also tried
const Home = ({route}, props) => {
{console.log(route.params.id)}
{console.log(props)}
}
By the way, I am using the latest version of React Native and React Navigation. I'm using purely functional component
Normally, I use to like that
const Home = (props) => {
const {route} = props
{console.log(route.params.id)}
{console.log(props)}
}
Because in component all params are props and only one param is props in component
this not the right way to pass other props. try this.
const Home =({route, ...props}) => {
....
}
I have a route which takes an id and renders the same component for every id, for example :
<Route path='/:code' component={Card}/>
Now the in the Link tag I pass in an id to the component.Now the Card component fetches additional detail based on the id passed. But the problem is it renders only for one id and is not updating if I click back and goto the next id. I searched and found out that componentsWillReceiveProps can be used but during recent versions of React it has been deprecated. So how to do this?
Putting current location as key on component solves problem.
<Route path='/:code' component={(props) => <Card {...props} key={window.location.pathname}/>}/>
I just ran into a similar problem. I think you are conflating updating/rerendering and remounting. This diagram on the react lifecycle methods helped me when I was dealing with it.
If your problem is like mine you have a component like
class Card extend Component {
componentDidMount() {
// call fetch function which probably updates your redux store
}
render () {
return // JSX or child component with {...this.props} used,
// some of which are taken from the store through mapStateToProps
}
}
The first time you hit a url that mounts this component everything works right and then, when you visit another route that uses the same component, nothing changes. That's because the component isn't being remounted, it's just being updated because some props changed, at least this.props.match.params is changing.
But componentDidMount() is not called when the component updates (see link above). So you will not fetch the new data and update your redux store. You should add a componentDidUpdate() function. That way you can call your fetching functions again when the props change, not just when the component is originally mounted.
componentDidUpdate(prevProps) {
if (this.match.params.id !== prevProps.match.params.id) {
// call the fetch function again
}
}
Check the react documentation out for more details.
I actually figured out another way to do this.
We'll start with your example code: <Route path='/:code' component={Card}/>
What you want to do is have <Card> be a wrapper component, functional preferrably (it won't actually need any state I don't think) and render the component that you want to have rendered by passing down your props with {...props}, so that it gets the Router properties, but importantly give it a key prop that will force it to re-render from scratch
So for example, I have something that looks like this:
<Route exact={false} path="/:customerid/:courierid/:serviceid" component={Prices} />
And I wanted my component to rerender when the URL changes, but ONLY when customerid or serviceid change. So I made Prices into a functional component like this:
function Prices (props) {
const matchParams = props.match.params;
const k = `${matchParams.customerid}-${matchParams.serviceid}`;
console.log('render key (functional):');
console.log(k);
return (
<RealPrices {...props} key={k} />
)
}
Notice that my key only takes customerid and serviceid into account - it will rerender when those two change, but it won't re-render when courierid changes (just add that into the key if you want it to). And my RealPrices component gets the benefit of still having all the route props passed down, like history, location, match etc.
If you are looking for a solution using hooks.
If you are fetching data from some API then you can wrap that call inside a useEffect block and pass history.location.pathname as a parameter to useEffect.
Code:
import { useHistory } from "react-router";
const App = () => {
const history = useHistory();
useEffect(() => {
//your api call here
}, [history.location.pathname]);
};
useHistory hook from react-router will give the path name so the useEffect will be called everytime it (url) is changed
as described by #theshubhagrwl but
you can use location.href instead of location.pathname to work in all condition
import { useHistory } from "react-router";
const App = () => {
const history = useHistory();
useEffect(() => {
// do you task here
}, [history.location.href]);
};
You can use use UseLocation() from "react-router-dom"
and then use that object in useEffect dependency array.
import {useLocation} from "react-router-dom";
export default function Card() {
const location = useLocation();
useEffect(()=>{}, [location]);
return(
// your code here
);
}
In React Router v4 Adding a Switch tag after Router fixes the problem
Here's what I have done so far,
This is the Route that I have defined for a page
<Route path='emails/user/view/:id' component={AccountEmails} />
And here's where the Component is being rendered
const AccountEmails = ({params: {id}}) => <ReceiptsListBox url={"/api/accounts/"+id+"/receipts.json"}></ReceiptsListBox>
Now, within the render() method of the component, I tried to console.log(this.props.location.query) unfortunately this.props.location is undefined.
Here's the YouTube video that I have referred to.
react-router version 2.8.1 and react version 15.3.2
Use this:
const AccountEmails = props => {
const {id} = props.params;
return <ReceiptsListBox
url={"/api/accounts/"+id+"/receipts.json"}
{...props} // =====> notice this part, important
</ReceiptsListBox>
}
Reason is: You are passing only url in props, not all the props values that AccountEmails receives from Routes, because of that location is not available inside ReceiptsListBox component.
Solution is pass all the props that AccountEmails component receive along with one extra url value, by that way location will be available inside ReceiptsListBox component.
How do I get the params of a route inside a react component
Im using react containers from the react composer package
if this is the whole route
https://learnbuildrepeat-tevinthuku.c9users.io/ReadProjectMeta/wD98XTTtpf8ceyRJT
How do I get only
wD98XTTtpf8ceyRJT
and store its value in a variable inside a react component.
Ive tried to use
FlowRouter.getParam() but it doesnt work. I keep getting undefined
import React from 'react';
export default class ReadProjectMetaLayout extends React.Component {
render() {
var category = FlowRouter.getQueryParam();
console.log(category);
return (
<div>
<h4>Hello World</h4>
</div>
)
}
}
this is the route
FlowRouter.route("/ReadProjectMeta/:_id", {
name: 'project.meta',
action(params) {
mount(ReadProjectMetaLayoutContainer, {
components: (<ReadProjectMeta _id={params._id}/>)
})
}
});
What could be the problem and how do I solve it
To only get the last part of the string:
location.pathname.substr((location.pathname.lastIndexOf('/')+1))
Another pure meteor based thing you can try is from this reference:
FlowRouter.getParam(":_id");
NOTE: Your solution didn't work as you are getting query parameter, query parameters are the parameters that are passed in the url after '?'
i.e. /apps/this-is-my-app?show=yes&color=red
Here in above code color and show are query parameters, while apps is a part of pathname
FlowRouter.getParam(paramName) returns the value of a single URL
parameter
FlowRouter.getQueryParam(paramName) returns the value of a single URL query parameter
Reference:
https://guide.meteor.com/routing.html#accessing-route-info