I have a React form which has the following form submission button:
<Link
className="btn btn-secondary btn-width-200 search-submit"
to={{pathname: '/booking/search', query: this.state.filters}}>
Search
</Link>
In the above link I want to call a function handleSubmit(evt) on button click.
handleSubmit(evt) {
evt.preventDefault();
this.setState({form_submitted: true});
}
<Link className="btn btn-secondary btn-width-200 search-submit" to={{pathname: '/booking/search', query: this.state.filters}} onClick={this.handleSubmit.bind(this)}>Search</Link>
But the following ignores the to={{pathname: '/booking/search', query: this.state.filters}} and just takes handleSubmit function into consideration
Is there anyway to add to={{pathname: '/booking/search', query: this.state.filters}} to the handleSubmit function? Or is there anyway to resolve this issue?
This 👇🏼 :
import {Link} from 'react-router';
handleSubmit(evt) {
evt.preventDefault();
this.setState({form_submitted: true});
}
<Link
className="btn btn-secondary btn-width-200 search-submit"
to={{pathname: '/booking/search', query: this.state.filters}}>
Search
</Link>
Can be replaced by 👇🏼 :
import {browserHistory} from 'react-router';
handleSubmit(evt) {
evt.preventDefault();
this.setState({form_submitted: true});
return this.redirect('/booking/search', this.state.filters);
}
redirect(to, query) {
browserHistory.push({pathname: to, query})
}
<a
className="btn btn-secondary btn-width-200 search-submit"
onClick={this.handleSubmit} >
Search
</a>
All you need to understand is, how to achieve route using react-router API. Basically you can configure it on two API, browserHistory and hashHistory. (link)
So, in otherword, by calling browserHistory.push('/booking/search') or hashHistory.push('/booking/search') you should be able to navigate between routes.
There is redux version also available, just in case if you want to manage your navigation via some action dispatch (though it is not necessary). Link
For more info: Programmatically navigate using react router
You can use the push router method in external Function instead of using Link. For example:
redirectFunction() {
this.handleSubmit()
router.push({
to: '/booking/search',
query: this.state.filters
})
}
render () {
<div
className="btn btn-secondary btn-width-200 search-submit"
onClick={this.redirectFunction.bind(this)}>
Search
</div>
}
Related
I have a NEXT.js app, After i select school .
Im tryna pass data to my vertical nav bar. It works fine, in dev mode.
But it the data is always undefined in production mode. The getdata function doesnt work. I think im doing something silly, instead of passing data down and down to components, is there a better way ?
Code :
App/school/[school_id]/page.tsx
async function Page(searchParams : unknown) {
Here im getting the the data from the <Link/> component
await getNavIDS(searchParams);
//here im tryna send my datqa to my navbar
return (
<>
<div className="row">
<div className="col-1">
21312312321231
</div>
</div>
</>
);
}
// NAVBAR COMPONENT
var navObject : any = {id:""};
export const getNavIDS = async(params : {}) => {
navObject= await params;
}
function Verticalnav() {
console.log()
return (
<>
<nav>
<Link href={{pathname:`school/${navObject.id}/students`}}><button type="button" className="btn btn-dark btn_size">All Students</button></Link>
</nav>
</>
)
}
export default Verticalnav
// I Have a page that displays cards. With a button which directs with the component , shown below
<div className='School_box'>
<Link href={{pathname:`school/${item.id}`, query: item}} ><button type="button" className="btn btn-secondary btn-lg">View School</button></Link>
</div>
</div>
I've tried adding a function to GRAB the data. but sometimes the navbar gets rerendered and i lose the props. I cannot find this on next.js docs .
Should i use a router instead ? NO IDEA. Some feedback would be appreciated
I am trying to write a function that sets the current location to the route that was just clicked. However, as you can see, it gives me the url of the page I was on WHEN I clicked the button, not the page of path of the button itself. What should I use instead of window.location.pathname?
const setLocation = () => {
console.log(window.location.pathname);
setCurrentLocation(window.location.pathname);
};
<Link onClick={() => setLocation()} to="/today" className="btn btn-primary btn-sm">
<Link onClick={() => setLocation()} to="/upcoming" className="btn btn-primary btn-sm">
Why are you storing this to the state ?
ReactRouter has a hook useLocation https://v5.reactrouter.com/web/api/Hooks/uselocation in which you can take .pathname of any pushed path to history.
If you really want to store location by yourself pass on the route value in to as a param in setLocation function or create a component that wraps the Link component and does store location : )
ie:
<Link onClick={() => setLocation("/upcoming")} to="/upcoming" className="btn btn-primary btn-sm">
code is like ===>
onClick={
(e)=>console.log(e.target.href)
setLocation(e.target.href)
}
const setLocation = (path) => {
console.log(window.location.pathname);
setCurrentLocation(window.location.pathname+path);
};
I am learning react-redux, I am creating a simple CRUD app using JSON placeholder, now I am able to display data and delete data using post and delete method's but I can't figure out how to update data with put method in redux, I need help.
**
Here is a live demo in the sandbox: redux live demo
**
Here is what I have so far, user component (just part of codes)
return(
<div>
<table id="users">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
{userData &&
userData.users &&
userData.users.map(user =>
<tbody>
{user.editing ? <UserForm user={user} key={user.id} />:
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>
<button key={user.id} type="button" className="btn btn-danger btn-link" onClick={() => deleteUser(user.id)}>
<i className="material-icons">delete</i>
</button>
<button key={user.id} type="button" className="btn btn-success btn-link" onClick={() =>editUser(user.id)}>
<i className="material-icons">edit</i>
</button>
</td>
</tr>
}
</tbody>
)}
</table>
</div>
)
And here is userfom component
import React from 'react'
import { useForm } from "react-hook-form";
function UserForm() {
const { edit, handleSubmit} = useForm();
return (
<div>
<form onSubmit={handleSubmit}>
<input name="name" defaultValue="test" ref={edit} />
<input type="submit" />
</form>
</div>
)
}
export default UserForm
And here is Edit user in reducer
case ActionTypes.EDIT_USER:
return{
...state,
users:state.users.map((user)=>user.id === action.payload ? {
...user,editing:!user.editing
}:user)
}
Now when I click edit and submit the data, it refreshes the page and nothing is updated in user info (check it here live
What is wrong with my code?
Well I don't have a lot of knowledge about react-hook-form but I'll try to help you, first you need to pass a function to your 'handleSubmit' because otherwise I think that you don't prevent the default behaviour of a submit, I mean the handleSubmit function doesn't do a 'event.preventDefault()', so you can put the following below your useForm hook:
const onSubmit = data => {
console.log(data);
}
Then in your jsx you will have
<form onSubmit={handleSubmit(onSubmit)}>
I'm not sure because as I told you I don't use react-hook-form, but I think another bug that I saw is that you are trying to get a 'edit' property from the useForm hook, well that won't work, you are not declaring a variable there, you are trying to access a property from the useForm hook, so in order of tracking the changes of your inputs you should use 'register', I mean you should have the following code:
const { register, handleSubmit } = useForm();
And you should update your jsx with the following:
<input name="name" defaultValue="test" ref={register} />
Now with every submit you will have your form with the changes in the console.log that we add in our onSubmit function.
You already connected redux with your Users component, I mean you are using mapDispatchToProps and because of that inside your Users components you will be able to access the edit prop to dispatch an editUser action. So in order to continue your work with redux you can pass that prop via this.props.editUser to your UserForm component and continue. Another option is connect the UserForm component with redux and access the editUser prop.
I've modified your code, update user can work now.
revised version demo
redux/user/Users
// need to pass whole user data as parameter
export const updateUser = data => {
return dispatch => {
axios
// add data into axios second arg
.put(`https://jsonplaceholder.typicode.com/users/${data.id}`, data)
.then(response => {
dispatch(editUser(data.id));
// refresh user list after successfully update
dispatch(fetchUsers());
})
.catch(error => {
const errorMsg = error.message;
dispatch(fetchUsersFailure(errorMsg));
});
};
};
components/UserForm:
You don't need react-hook-form, just use the useDispatch hook that provided by react-redux.
import React from "react";
import { useDispatch } from "react-redux";
import { editUser, updateUser } from "../redux/acitons/users/Users";
function UserForm({ user }) {
const dispatch = useDispatch();
const [name, setName] = React.useState(user.name);
const handleSubmit = () => {
dispatch(updateUser({ ...user, name }));
};
const handleCancel = () => {
dispatch(editUser(user.id));
};
return (
{/* I modify it to inline edit row */}
<tr>
<td>{user.id}</td>
<td>
<input
defaultValue={user.name}
onChange={e => setName(e.target.value)}
/>
</td>
<td>
<button type="button" className="btn" onClick={handleCancel}>
<i className="material-icons">Cancel</i>
</button>
<button
type="button"
className="btn btn-success btn-link"
onClick={handleSubmit}
>
<i className="material-icons">save</i>
</button>
</td>
</tr>
);
}
export default UserForm;
But you will notice that new user list is still old after update successfully, this is normal
https://github.com/typicode/jsonplaceholder/issues/42#issuecomment-284507310
and I suggest you can group your actions/reducer/constants into one file by feature, this is useful when your app grow, You can easily find the file you want to modify when your code base becomes very large.
for example:
|-- reducers
|---- auth.js
|---- counter.js
|---- index.js
|---- store.js
|---- users.js
This approach actually has a name called duck pattern
In my app.js for the button component I gave this props propTwo={"two"}
but still Button.js nothing is printing inside componentWillReceiveProps
can yoi tell me how to recieve the props using componentWillReceiveProps method
can you tell me how to use componentWillReceiveProps in my application
providing my code snippet and sandbox below
https://codesandbox.io/s/hopeful-villani-xyikq
class Button extends Component {
componentWillReceiveProps(nextprops) {
console.log("componentWillReceiveProps nextprops--->", nextprops);
}
render() {
return (
<div>
<button
onClick={() => {
// getPosts(channel);
// getAlert();
}}
className="btn btn-primary btn-lg btn-block"
>
Get top news
</button>
</div>
);
}
}
App.js
const App = () => (
<div>
<RecentChannelItem />
<ChannelsField propOne={"one"} />
<Button propTwo={"two"} />
<TopNews />
</div>
);
componentWillReceiveProps is already deprecated.
You can use componentDidUpdate.
You can access the updated props by accessing this.props inside the componentDidUpdate.
You should use:
static getDerivedStateFromProps(nextprops) {
console.log("componentWillReceiveProps nextprops--->", nextprops);
}
I am working on gatsby. I need to go back to privious page/link as I used to do with reactjs.
<a onClick={() => this.props.history.goBack}>
<button type="button" className="close_tab">
<img src={Close} alt="" />
</button>
</a>
How can I do this using gatsby?
Use navigate(-1):
import React from "react";
import { navigate } from "gatsby";
export default function GoBack() {
return (
<Button onClick={() => navigate(-1)}>
Go Back
</Button>
);
}
Edit: Since reach-router#1.3.0, you can now simply call navigate(-1) to go back. Manually update reach-router in your Gatsby project if it's not yet updated. Thanks #nathan in the comment for the tip.
Edit: Ah alright, I've just realized this.props.history.goBack is a react-router thing. Gatsby doesn't use react-router, but reach-router under the hood and it doesn't have the history props or the goBack method. There's a issue requesting to add this, but wasn't implemented. You'd have to use browser's own history object as I suggested below.
import React from 'react'
const BackButton = React.forwardRef(
({ children, ...props }, ref) => {
const onClick = e => {
e.preventDefault()
history.back()
}
return (
<a {...props} ref={ref} href="#" onClick={onClick}>
{children}
</a>
)
}
)
BackButton.displayName = 'BackButton'
export { BackButton }
Is this.props.history the browser's history? If so, you can do this.props.history.go(-1) to go back to the previous page.
As always with Gatsby, watch out when you use methods from browser, since they don't exist during html generation:
export default () => (
<button onClick={() => {
typeof history !== 'undefined' && history.go(-1)
}}>back</button>
)
For a function component in Gatsby:
<a onClick={() => window.history.back()}>Go back</a>
The gatsby navigate function is type as NavigateFn.
Which you can find declare as:
export interface NavigateFn {
(to: string, options?: NavigateOptions<{}>): Promise<void>;
(to: number): Promise<void>;
}
So, as you can see, you either can pass the route you want to redirect to, or an specific number.
Try with navigate(-1)
This should work
import { navigate } from "#gatsbyjs/reach-router";
<button onClick={() => navigate(-1)}>Back to previous page</button>
It goes to the previous page