Search code examples
javascriptreactjsreact-hooksfetchreact-context

How do t use match props in react js while using context api


I'm creating a basic app and i used context api, fetch, react hooks for all the component except the context api component because, i'm still learning to use hooks.

I fetched my data from the backend, i want to use one component for my create and update of my data, my major problem is that i don't know how to use the match prop inside the contextApi provider to get the id for editform and singleItem using params. I created a function that calls a singleItem and i passed it to my form component, so it can be the initial value in case of editing but it didn't work. I got an error Unhandled Rejection (TypeError): Cannot read property 'params' of undefined.

my context api component

import React, { Component, createContext } from 'react'

export const ContactContext = createContext()

export class ContactContextProvider extends Component {

  state = {
    Contact : [],

    singleContact:{}

  }

  componentDidMount(){
    fetch('http://127.0.0.1:5000/Contact')
    .then(res=>res.json())
    .then(data=>{
      this.setState({
        Contact:data
      })
      
    })

    this.getSingleItem()
    
  }

  getSingleItem = async() => {
    const fetch_id = await fetch(`http://127.0.0.1:5000/Contact/${this.props.match.params.id}`)
    const data = await fetch_id.json()

    this.setState({singleContact:data})

  }

  createContact = (item) =>{
    const req = {
      method : 'POST',
      headers : {'Content-Type':'application/json'},
      body: JSON.stringify(item)
    }
    fetch('http://127.0.0.1:5000/Contact/add', req)
    .then(res=>res.json())
    .then(data=> data)
  }

  editContact = (item) => {
    const req = {
      method : 'POST',
      headers : {'Content-Type' : 'application/json'},
      body : JSON.stringify(item)
    }
    fetch(`http://127.0.0.1:5000/Contact/edit/${this.props.match.params.id}`)
    .then(res=>res.json())
    .then(data=>console.log(data))
  }
  
  deleteContact =  (_id) => {
    fetch(`http://127.0.0.1:5000/Contact/${_id}`, {method:'DELETE'})
    .then(res=>res.json())
    .then(data=>console.log(data))
   

    this.setState({
      Contact : [...this.state.Contact.filter(item => item._id !== _id)]
    })
  }

  

  render() {
    return (
      <ContactContext.Provider value={{...this.state, createContact:this.createContact, editContact:this.editContact, deleteContact:this.deleteContact}}>
        {this.props.children}
      </ContactContext.Provider>
    )
  }
}

export default ContactContextProvider

This is my form for creating and editing data


import { Form, Button, Col} from 'react-bootstrap';
import React, {useState, useContext} from 'react'
import { ContactContext } from '../context/ContactContext';

function Contactform() {
  const {createContact, singleContact, editContact} = useContext(ContactContext)

  const [Contact, setContact] = useState({
    firstName: singleContact.firstName || '',
    lastName: singleContact.lastName || '',
    company: singleContact.company || '',
    phone: singleContact.phone || '',
    email: singleContact.email || '',
    note: singleContact.note || ''
  

  })
  
  const handleChange = (e) =>{
    setContact((prevState)=>({
      ...prevState,
      [e.target.name]:e.target.value
    }))
  }

  const handleSubmit = (e) =>{
    e.preventDefault()
    const item = {
      firstName: Contact.firstName,
      lastName: Contact.lastName,
      company: Contact.company,
      phone: Contact.phone,
      email: Contact.email,
      note: Contact.note
     
      
    }

    if(Contact===''){
      createContact(item)
    }
     else {
       editContact(item)
     }
  }
  
  return (
    
    <Form id='form' onSubmit={handleSubmit} >
      <Form.Row>
    <Form.Group as={Col} >
      <Form.Label>First Name</Form.Label>
      <Form.Control name='firstName' value={Contact.firstName} onChange={handleChange} type="text" placeholder="First Name" />
    </Form.Group>
    <Form.Group as={Col} >
      <Form.Label>Last Name</Form.Label>
      <Form.Control name='lastName' value={Contact.lastName} onChange={handleChange} type="text" placeholder="Last Name" />
    </Form.Group>
    </Form.Row>
    <Form.Row>
    <Form.Group as={Col} >
      <Form.Label>Company</Form.Label>
      <Form.Control name='company' value={Contact.company} onChange={handleChange} type="text" placeholder="Company" />
    </Form.Group>
    <Form.Group as={Col} >
      <Form.Label>Phone</Form.Label>
      <Form.Control name='phone' value={Contact.phone} onChange={handleChange} type="text" placeholder="Phone" />
    </Form.Group>
    </Form.Row>
    <Form.Row>
    <Form.Group as={Col} >
      <Form.Label>Email</Form.Label>
      <Form.Control name='email' type="email" value={Contact.email} placeholder=" email" onChange={handleChange} />
    </Form.Group>
   
    </Form.Row>
   
   
    <Form.Group >
      <Form.Label>Note</Form.Label>
      <Form.Control as="textarea" name='note' value={Contact.note} onChange={handleChange}  rows={3} placeholder='Note'/>
    </Form.Group>
    
    
    <Button  id='form_btn' variant="primary"  type="submit">
      Submit
    </Button>
  </Form>
    )

  
}

export default Contactform

Solution

  • You can simply do this. I am assuming you are already using react-router. You can simply use withRouter hoc. It will pass all router props.

    //Your context api component

    import React, { Component, createContext } from 'react'
    import { withRouter } from "react-router";
    
    export const ContactContext = createContext()
    
    class ContactContextProvider extends Component {
    
      state = {
        Contact : [],
    
        singleContact:{}
    
      }
    
      componentDidMount(){
        fetch('http://127.0.0.1:5000/Contact')
        .then(res=>res.json())
        .then(data=>{
          this.setState({
            Contact:data
          })
          
        })
    
        this.getSingleItem()
        
      }
    
      getSingleItem = async() => {
        const fetch_id = await fetch(`http://127.0.0.1:5000/Contact/${this.props.match.params.id}`)
        const data = await fetch_id.json()
    
        this.setState({singleContact:data})
    
      }
    
      createContact = (item) =>{
        const req = {
          method : 'POST',
          headers : {'Content-Type':'application/json'},
          body: JSON.stringify(item)
        }
        fetch('http://127.0.0.1:5000/Contact/add', req)
        .then(res=>res.json())
        .then(data=> data)
      }
    
      editContact = (item) => {
        const req = {
          method : 'POST',
          headers : {'Content-Type' : 'application/json'},
          body : JSON.stringify(item)
        }
        fetch(`http://127.0.0.1:5000/Contact/edit/${this.props.match.params.id}`)
        .then(res=>res.json())
        .then(data=>console.log(data))
      }
      
      deleteContact =  (_id) => {
        fetch(`http://127.0.0.1:5000/Contact/${_id}`, {method:'DELETE'})
        .then(res=>res.json())
        .then(data=>console.log(data))
       
    
        this.setState({
          Contact : [...this.state.Contact.filter(item => item._id !== _id)]
        })
      }
    
      
    
      render() {
        return (
          <ContactContext.Provider value={{...this.state, createContact:this.createContact, editContact:this.editContact, deleteContact:this.deleteContact}}>
            {this.props.children}
          </ContactContext.Provider>
        )
      }
    }
    
    export default withRouter(ContactContextProvider)