Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass all state variables inside react hooks to my child component

I am trying to get all the states within the functional components using hooks. Equivalent to ...this.state. I am avoiding passing the state individually to the Context.Provider.

Since this.state is not available within the function. state is undefined.

import React, { useState, useEffect } from 'react'

const RecipeContext = React.createContext()

const RecipeProvider = (props) => {
  const [showHomeButton, setShowHomeButton] = useState(false)
  const [recipes, setRecipes] = useState([])
  const [loading, setLoading] = useState(true)
  const [search, setSearch] = useState('')


  const fetchRecipe = async () => {
    const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`)
    const { recipes } = await recipeData.json()
    setRecipes(recipes)
    setLoading(false)

  }
  const handleSubmit = async (e) => {
    e.preventDefault()
    setLoading(true)
    url = `${url}&q=${search}`
    fetchRecipe(url)
    setShowHomeButton(true)

  }
  const handleSearchChange = (e) => {
    setSearch(e.target.value)
  }
  const handleReturnHome = () => {
    fetchRecipe()
  }
  useEffect(() => {
    fetchRecipe()

  }, [])
  return (
    <RecipeContext.Provider value={}>
      {props.children}
    </RecipeContext.Provider>
  )
}
const RecipeConsumer = RecipeContext.Consumer
export { RecipeProvider, RecipeConsumer }

What's best way to pass all the states within the component to value in the provider.

 <RecipeContext.Provider value={}>
      {props.children}
    </RecipeContext.Provider>
like image 805
Ola John Ajiboye Avatar asked Jul 03 '19 17:07

Ola John Ajiboye


People also ask

How do you pass data to child component React hooks?

First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.

How do you pass state variables as props in React hooks?

Passing props to state using useState Hooks import React, { useState } from 'react'; const Profile = props => { const [profileState, setProfileState] = useState(props); return ( <div> <p> <strong>Name:</strong> {profileState.name} </p> <p> <strong>Email:</strong> {profileState.

Can you pass useState to child?

You can pass the state as props, but if you want child components to alter state, then you can pass the setter from the useState directly to child components.


2 Answers

Use an object as the state

const RecipeProvider = (props) => {
  //Declare an object as the state
  const [megaState, setMegaState] = useState({
      showHomeButton: false,
      recipes : [],
      loading : true,
      search: ''
  })



  const fetchRecipe = async () => {
    const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`)
    const { recipes } = await recipeData.json()

    //UPDATE STATE WITHOUT MUTATING
    setMegaState({
        ...megaState
        recipes,
        loading: false
    })    
  }
  const handleSubmit = async (e) => {
    e.preventDefault()
    setLoading(true)
    url = `${url}&q=${search}`
    fetchRecipe(url)
    setShowHomeButton(true)
    //UPDATE STATE WITHOUT MUTATING
    setMegaState({
        ...megaState
        showHomeButton : true 
    })
  }
  const handleSearchChange = (e) => {
    //UPDATE STATE WITHOUT MUTATING
    setMegaState({
        ...megaState
        search : e.target.value 
    })
  }
  const handleReturnHome = () => {
    fetchRecipe()
  }
  useEffect(() => {
    fetchRecipe()

  }, [])
  return (
    <RecipeContext.Provider value={megaState}>
      {props.children}
    </RecipeContext.Provider>
  )
}

This can be further improved by using useReducer! :)

like image 87
Dehan Avatar answered Oct 05 '22 13:10

Dehan


You already have many states. Don't use useState as you were using the setState function from classes.

An advice, If you don't wanna get confused and work with useState like you were using the setState from classes, use the same "labels" for the variable and try, if you can, to have one state.

// From this
const [showHomeButton, setShowHomeButton] = useState(false);
const [recipes, setRecipes] = useState([]);
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');

// to this - common understanding
const [state, setState] = useState({
  showHomeButton: false,
  recipes: [],
  loading: true,
  search: '',
});

(Less code, easy to maintain)

About avoiding to passing the state through the Context Provider; it's not an option you have to. Otherwise, there's no reason to use it.

What I would do, it would be to keep the rest of your code and change the last lines of code. Having something like this:

(btw, your fetchRecipe function is not receiving a parameter)

import React, { useState, useEffect } from 'react'

const RecipeContext = React.createContext()

const RecipeProvider = (props) => {
  const [state, setState] = useState({
    showHomeButton: false,
    recipes: [],
    loading: true,
    search: '',
  });

  const fetchRecipe = async () => {
    const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`);
    const { recipes } = await recipeData.json();
    setState({
      ...state,
      recipes,
      loading: false,
    });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    fetchRecipe(`${url}&q=${search}`);

    setState({
      ...state,
      loading: true,
      showHomeButton: true
    });
  }

  const handleSearchChange = (e) => {
    e.persist();

    setState({
      ...state,
      search: e.target.value
    });
  };

  // this might not needed
  const handleReturnHome = () => {
    fetchRecipe()
  };

  useEffect(() => {
    fetchRecipe()

  }, []);

  return (
    <RecipeContext.Provider value={{
      store: state,
      actions: {
         fetchRecipe,
         handleSearchChange,
         handleSubmit,
      }
     }}>
      {props.children}
    </RecipeContext.Provider>
  )
}

export default RecipeProvider;

Of course this is just and example. You could also make use of useReducer like someone says. This way you could treat your local state like you were working with Redux.

Now you have two options depending if you are using an Stateful or Stateless component. For Stateful component: Get access to the context (value) of your provider using:

<RecipeContext.Consumer>
  {value => (
   <SomeComponent />
  )}
</RecipeContext.Consumer>

// OR

class SomeComponent extends Component {
  render() {
   let value = this.context;
  }
}
SomeComponent. contextType = RecipeContext;

For Stateless components:

const SomeComponent = props => {
  const value = useContext(RecipeContext);
};

What I explained above it could be found here: https://es.reactjs.org/docs/hooks-reference.html#usecontext. Also in the link, you will find an example of how to use useReducer. That would be great in this case, instead of passing all the functions as I did, you could pass one single action dispatch and pass a type as the action you wanna trigger and get a new state from it.

But, you HAVE TO use the value from the context Provider.

like image 34
Diego Molina Avatar answered Oct 05 '22 13:10

Diego Molina