What is the right way to use new React hook useContext?
Asked Answered
T

4

6

I have some difficulties to understand the new way to use react Context API. I have an app with a custom class Firebase. Now I want to make a hook to pass it. Before I used HOC (higher-order Component) and context.

My questions

  1. Do I need to use HOC or it's a new way to do this?
  2. Do I need the Context.Provider or it's new Hook?
  3. Do I need to declare default value as a null or I can pass my Object right from context.js
  4. How can I use a new Hook instead of HOC in mine code?

Here is my code with some comments related to questions

// context.js this is my hoc
// index.jsx
import App from './App'
import Firebase, { FirebaseContext } from './components/Firebase'

const FirebaseContext = React.createContext(null)

export const withFirebase = Component => (props) => {
  // I don't need to wrap it to the FirebaseContext.Consumer
  // 1 But do I need this HOC or it's a new way?
  const firebase = useContext(FirebaseContext)
  return <Component {...props} firebase={firebase} />
}

ReactDOM.render(
  // 2 Here I'm lost. Do I need the FirebaseContext.Provider or not?
  // 3 Do I need to declare value her or I should do it in context.js as a default?
  <FirebaseContext.Provider value={new Firebase()}>
    <App />
  </FirebaseContext.Provider>,
  document.getElementById('root'),
)

// App.jsx
// 4 Can I use a new Hook instead of HOC here and how?
import { withFirebase } from './components/Firebase/context'
const App = () => {
    const firebase = this.props.firebase // But should be useContext(FirebaseContext) or something like this?
    return(...)
}
export default withFirebase(App) // I don't need this with the Hook

Any help appreciated.

Tyrocidine answered 19/2, 2019 at 4:14 Comment(6)
Stack overflow is not a tutorial website. I recommend setting up a new question for each of your questions. Make some attempt to solve the problem and if you get stuck we can help.Cribbing
It looks like you want a beginners introduction to using the context hook, for which I would recommend Dave Ceddia's https://daveceddia.com/usecontext-hook/Cribbing
useContext is just an alternative to Context.Consumer or myClass.contextType. Use the variable and pass the context reference into it as default.Cloudburst
@JoshPittman I've seen this tutorial (and few more) but still have these questions. I think it's nice to put all together because I use context as I described (it works) and want to show where I'm not sure how to use it.Tyrocidine
@KenoClayton that's clear for me. but do I need to wrap the App to Provider?Tyrocidine
You have misunderstood what stack overflow is for, please rephrase your question to address a specific reproducible problem that we can help you debug and solve. Help with a general understanding of how things work is not what stack is for.Cribbing
D
8

You should understand it first that, useContext is just to make use of Context and acts like a consumer and not Provider.

To answer your questions

Do I need to use HOC or it's a new way to do this?

You don't need an HOC with hooks. Hooks are meant to replace HOCs and render props pattern.

Do I need the Context.Provider or it's new Hook?

There is no hooks equivalent of Context.Provider. You have to use it as is.

Do I need to declare default value as a null or I can pass my Object right from context.js

The default value to createContext is only used if you don't pass a value props to the Context.Provider. If you pass it the default value is ignored.

How can I use a new Hook instead of HOC in mine code?

Instead of using useContext in the component returned by HOC use it directly within the component

Sample code

/ context.js this is my hoc
// index.jsx
import App from './App'
import Firebase, { FirebaseContext } from './components/Firebase'

const FirebaseContext = React.createContext(null)

ReactDOM.render(
  <FirebaseContext.Provider value={new Firebase()}>
    <App />
  </FirebaseContext.Provider>,
  document.getElementById('root'),
)

App.jsx

const App = () => {
    const firebase = useContext(FirebaseContext) 
    return(...)
}
export default App;
Diplegia answered 19/2, 2019 at 5:23 Comment(7)
Thank you. That's work. One more thing. How to pass the default value? if I try Provider without it it's undefined.Tyrocidine
One more thing. How to pass the default value if you don't pass the value prop to FirebaseContext.Provider you can specify the default value as argument to React.createContextDiplegia
So I can just leave App without Provider and use the default value (Firebase is always the same)? Is it a good practice?Tyrocidine
I tested and it works. Provider without the value prop will pass undefined. have a look it's in docs reactjs.org/docs/context.html#reactcreatecontext The defaultValue argument is only used when a component does not have a matching Provider above it in the tree.Tyrocidine
Sorry my mistake. I got confused with something else. Thanks for informingDiplegia
Hi @ShubhamKhatri I have a Context for Theme and almost every(50+) components are using Theme Context using HOC, what would you prefer in code, 50 line of code of export default withTheme(MyComponent); or function MyComponent(){ const theme = useContext(ThemeContext); //...}Gurl
@sanjeev As react docs state, you can write your existing components using hooks and avoid rewriting existing components. Using hocs and debugging them with react devtools is a little move overhead than hooks but otherwise there shouldn't be any issue keeping extra lines of codeDiplegia
R
0
  1. Do I need to use HOC or it's a new way to do this?

No, you don't need to use HOC as best technique.

Why? Starting from React v7.0, you can use functional-based components. From this version efficient is to use the the latest technique named HOOKS, which were designed to replace class and provide another great alternative to compose behavior into your components.


  1. Do I need the Context.Provider or it's new Hook?

Hook like useContext() has a relation with Context.Provider.
Context is designed to share data that can be considered “global”.

The Provider component accepts a value prop to be passed. Every Context come with a Provider.

Context.Provider component available on the context instance is used to provide the context to its child components, no matter how deep they are.


  1. Do I need to declare default value as a null or I can pass my Object right from context.js?

No, you don't need necessarily to declare a default value.

Example of defining the context in one corner of the codebase without defaultValue.

const CountStateContext = React.createContext() // <-- define the context without defaultValue


  1. How can I use a new Hook instead of HOC in mine code?

index.jsx

import App from './App'

import Firebase, { FirebaseContext } from './components/Firebase'

const FirebaseContext = React.createContext(null)

ReactDOM.render(
  <FirebaseContext.Provider value={new Firebase()}>
    <App />
  </FirebaseContext.Provider>,
  document.getElementById('root'),
)

Root Component: App.js, where will be used data comes form context:

const App = () => {
    const firebase = useContext(FirebaseContext) 
    return(...)
}
export default App;
Recant answered 11/1, 2022 at 15:46 Comment(0)
M
0
import About from './About'
import React, { createContext, useContext, useState } from 'react'
import {colorThem} from '../App'

const listData =createContext()

const Home = () => {
    const [list , seTList]=useState([1,2,3,4,5,6,7,8,9])
    const data = useContext(colorThem)
  return (
    <div>
        <h1>I'm From Home {data}</h1>
        <listData.Provider value={list}>
        <About/>
        </listData.Provider>
    </div>
  )
}

export default Home
export {listData}


 import { useContext } from "react"
 import { listData } from "./Home"

const About = () => {
const arr = useContext(listData)
 console.log(arr)
  return (
    <div>
      <h1>About components </h1>
    {
        arr.map((item ,index)=><h1 key={index}>{item}</h1>)
    }
    </div>
  )
}

export default About
Mannerheim answered 30/5, 2023 at 17:16 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Mussman
S
0

Here is the tested code for useContext, In this example I am updating the form data and rendering the form data in different component.

import React, {createContext, useReducer, useContext} from 'react';

// CREATING THE CONTEXT
const userContext = createContext(null);

// REDUCER FUNCTION FOR UPDATING THE CONTEXT
const reducerFn = (state = [], payload) => {
    switch (payload.type) {
        case 'FIRST_NAME':
            return {...state, formData: {firstName: payload.payload, lastName: state.formData.lastName}}
        case 'LAST_NAME':
            return {...state, formData: {firstName: state.formData.firstName, lastName: payload.payload}}
    
        default:
            return {...state};
    }
}

// CONTEXT PROVIDER COMPONENT TO PASS THE CONTEXT VALUE 
const AppContextProvider = ({children}) => {
    const [state, dispatch] = useReducer(reducerFn, {formData: {firstName: '', lastName: ''}});
    return(
        <userContext.Provider value={{state, dispatch}}>
            {children}
        </userContext.Provider>
    )
}

// ACTION CREATION 
const updateFname = (val) => {
    return {
        type: 'FIRST_NAME',
        payload: val
    }
}

const updateLname = (val) => {
    return {
        type: 'LAST_NAME',
        payload: val
    }
}
// ACTION CREATION 



// FORM COMPONENT AND UPDATING THE FORMDATA USING CONTEXT
const UserForm = () => {
    const {state, dispatch} = useContext(userContext)
    return (
        <>
            <div>
                <label htmlFor='fname'>First Name</label>
                <input type='text' id='fname' onChange={(e) => dispatch(updateFname(e.target.value))}/>
            </div>
            <div>
                <label htmlFor='lname'>Last Name</label>
                <input type='text' id='lname' onChange={(e) => dispatch(updateLname(e.target.value))}/>
            </div>
            
        </>
    )
}

// COMPONENT FOR DISPLAYING THE FORMDATA
const DisplayFormData = () => {
    const {state, dispatch} = useContext(userContext);
    return(
        <div>
            <p>First Name is : {state.formData.firstName} and last Name is {state.formData.lastName}</p>
        </div>
    )
}

// MAIN COMPONENT
function Question3Context(props) {
    return (
        <div>
            <AppContextProvider>
                <UserForm />
                <DisplayFormData />
            </AppContextProvider>
        </div>
    );
}

export default Question3Context;
Sudden answered 6/8, 2023 at 16:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.