import React, { useContext } from "react";
import { ContextProvider, MyContext } from "./Context/MyContext";
import "./styles.css";
export default function App() {
const value = useContext(MyContext);
console.log(value);
return (
<ContextProvider>
<div className="App">{value}</div>
</ContextProvider>
);
}
If I want to consume the useContext exactly on App Component. I get the value as undefined on App Component but the value of all other component is okay. So, I want to know what is the mechanism behind it. Why I can't access to useContext in App component.
The ContextProvider provides the values within your Context to all it's child components. The value you are supplying to your <div> comes from the parent component of ContextProvider in your case, ie the App. At this point your Provider has still not been set up, you have to wrap App inside provider to access the values of the context. In other words the Provider needs to be the Parent of app to provide it values and not the other way around
Related
I'm learning React and I have a problem trying to read my props in a child component.
The child component is:
const HelloWorldApp = ( props ) => {
console.log(props);
return (<>
<h2> {props} </h2>
</>
);
}
export default HelloWorldApp;
The parent is:
import React from 'react';
import {createRoot} from 'react-dom/client';
import HelloWorldApp from './FirstApp';
import { SecondApp } from './SecondApp';
import './styles.css';
createRoot(document.getElementById('root')).render(HelloWorldApp());
createRoot(document.getElementById('raiz')).render(SecondApp());
1) What is the problem?
2) How can I pass props from the parent to the children component?
I think the problem is in the render function. You need something like this:
createRoot(document.getElementById('root'))
.render(<HelloWorldApp />);
In react , you don't need to render all the components in separate CreateRoot..
render your child component with props inside the parent component
The parent Component
import React from 'react';
import {createRoot} from 'react-dom/client';
import HelloWorldApp from './FirstApp';
import './styles.css';
createRoot(document.getElementById('root')).render(<HelloWorldApp data="propsData" />);
The child Component
const HelloWorldApp = ( props ) => {
console.log(props);
// {data: "dummyData"}
return (<>
// you can't able to render object inside the jsx
<h2> {props.data} </h2>
</>
);
}
export default HelloWorldApp;
The structure React program is on constantly changing over the time, whereby i recommend you use command npm create-react-app to have the latest standards of programming in that framework.
Only one createRoot is necessary in React renderize DOM, and i recommend you receive parameters with destructuring in child component, the parameters must been passed in JSX tags as attributes
The following React component is given:
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { store, StoreState } from "../../redux/actions";
import { setBackgroundAction } from "../../redux/title.actions";
import "./Loader.scss";
interface ReduxProps {
bgClass: string;
}
interface Props extends ReduxProps {
bgChange?: boolean;
}
export default function Loader(props: Props) {
const [bgClassOld, setBgClassOld] = useState<string>("");
const dispatch = useDispatch();
useEffect(() => {
const { bgChange, bgClass } = props;
if (bgChange) {
setBgClassOld(bgClass);
dispatch(setBackgroundAction("bg-white"));
dispatch(setBackgroundAction(bgClassOld));
}
});
return (
<div className="d-flex">
<div className="loader">
<img src="/loadscreen.gif" />
</div>
</div>
);
}
// function mapping(state: StoreState): ReduxProps {
// return {
// bgClass: state.title.backgroundClass,
// };
// }
This is more a theoretical question to see how to actually do the following change:
The component Loader will be imported from another npm package (shared components).
My problem is that I have a redux state in the current implementation included (changed it from Class to Functional component, so thats mapping() is still in there).
As I only import the component in my "main" client, I will not have the whole redux setup in place. So I think I need to pass the store and the dispatch functions via props.
So should I create a prop store for my component, where I pass the redux store when I import the shared component?
Do I also create two props for each dispatch functions?
Does is make sense or would there be a better approach?
You generally shouldn't import the Redux store directly into components. The hooks allow your component to access whatever Redux store has been injected into the component tree by a <Provider>.
You also don't need to pass dispatch as a prop. Any component can call useDispatch(), and dispatch actions to whatever Redux store is actually being used.
If I understand your question, you're planning on importing this component into an existing app, and it sounds like that app is already configured to use (React-)Redux with a <Provider> at the top. If that's the case, then you don't have to do anything else special to make this work. Just call the React-Redux hooks in any of your components.
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
Do I need to use HOC or it's a new way to do this?
Do I need the Context.Provider or it's new Hook?
Do I need to declare default value as a null or I can pass my Object
right from context.js
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.
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;
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.
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.
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
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;
I do not want to separate components when I am using react-navigation with redux.
How can I make a "const=" rather than make a new file and "export default"
const IntroScreen2 =connect(mapStateToProps,mapDispatchToProps)(IntroScreen2a)
const IntroScreen2 =()=> connect(mapStateToProps,mapDispatchToProps)(IntroScreen2a)
export default connect ...
which one is right?
https://codeshare.io/G79NRk
Do it something like this, define the component in the same file as where you use a default export of connect, passing in the component defined in the file.
These statements should help clear up your misunderstanding(s).
With react navigation, you have screens (components), and you have navigators. Navigators are created with screens (components).
You use react-redux's connect function to connect components to the redux store. You simply wrap a component in a call to connect, and export the return value of that, rather than the component itself.
When you create a navigator, you will need to import the components for your screens.
See the follow three pages, we make a component, export the component connected to the redux store, via react-redux's connect function.
Then we make a router, which exports a single stack navigator from react navigation, which defines a single screen, the component defined (mentioned above).
Then I have given an example of how you'd render that router, for example, inside your App.js.
some-component.js
import React, {Component} from "react";
import {connect} from "react-redux"
// Define the component
class SomeComponent extends Component {
render() {
return null;
}
}
// Map dispatch to props
const mapDispatchToProps = (dispatch) => {
return {};
}
// Map state to props
const mapStateToProps = (state) => {
return {};
};
// Export the component, passed into the connect function from react-redux.
export default connect (mapStateToProps, {}) (SomeComponent);
Then just import this file when defining your navigator with react navigation.
For example
router.js
import SomeComponent from "./some-component.js";
import {createStackNavigator} from "react-navigation";
export default createStackNavigator({
PageOne: {
screen: SomeComponent
}
});
In your App.js (root level)
import React, {Component} from "react";
import Router from "./router.js";
export default class App extends Component {
render () {
return <Router/>;
}
}
Something like that should get you sorted!
I have started learning basic of Context API in ReactJS.
This is a part of reactJS code which uses reactJS.
app.js
import React from 'react';
import ReactDOM from 'react-dom';
import LeftPane from './LeftPane';
import RightPane from './RightPane';
import {SampleProvider} from './sample';
const App =()=>{
return(
<SampleProvider>
<div className="panes">
<LeftPane/>
<RightPane/>
</div>
</SampleProvider>
)
}
export default App;
ReactDOM.render(
<App/>,
document.getElementById('root')
)
RightPane.js
RightPane.js
import React from 'react';
import Receives from './Receives';
const RightPane =()=>{
return(
<div className="pane">
<Receives/>
</div>
)
};
export default RightPane;
sample.js
import React,{Component , createContext} from 'react';
const Context = createContext();
const {Provider, Consumer : SampleConsumer}=Context;
class SampleProvider extends Component{
state={
value:'default value'
}
actions={
setValue:(value)=>{
this.setState({value});
}
}
render(){
const {state,actions}=this;
const value={state,actions};
return(
<Provider value={value}>
{this.props.children}
</Provider>
)
}
}
export{
SampleProvider,
SampleConsumer
};
Receives.js
import React from 'react';
import {SampleConsumer} from './sample';
const Receives = ()=>{
return(
<SampleConsumer>
{
(sample)=>(
<div>
Value:{sample.state.value}
</div>
)
}
</SampleConsumer>
)
}
console.log(Receives);
export default Receives;
Everything is fine. I understand everything except the function in SampleConsumer
component.
function in SampleConsumer uses sample as parameter.
I tested and sample.state.value renders 'default value' and it is the value of the state which is declared in SampleProvider component.
SampleProvider passes down the state as props to Provider component. I understand
Provider can use that state. But how the parameter in SampleConsumer understands
state in SampleProvider component? I have never passed the state as props to
SampleProvider component ..(I understood so. Maybe it's wrong)
I read this documentation
https://reactjs.org/docs/context.html
but didn't understand 100%
Everything is fine. I understand everything except the function in SampleConsumer component.
You have set SampleConsumer to point to the raw Consumer output of createContext(). It will function exactly the same as the ThemeContext.Consumer example in the docs.
function in SampleConsumer uses sample as parameter. I tested and sample.state.value renders 'default value' and it is the value of the state which is declared in SampleProvider component.
You have wrapped the raw Provider output of createContext() with your SampleProvider component. As you did so, you set the Provider's context value to (initially) be:
{
state: {
value: 'default value'
},
actions: {
setValue: (value) => { this.setState({value}) }
}
}
Meaning that whenever you invoke SampleConsumer that is a child of SampleProvider, the argument in the "child as a function" will be passed that value. In other words, this would display the string representation of the object in the above snippet:
<SampleConsumer>
{ (value) => <div>{value.toString()}</div> }
</SampleConsumer>
SampleProvider passes down the state as props to Provider component. I understand Provider can use that state.
Correct - you have set Provider's value prop to be equal to an object that contains SampleProvider's state.
But how the parameter in SampleConsumer understands state in SampleProvider component?
This is exactly what the context API accomplishes. SampleConsumer has access to Provider's value prop, without needing to pass the prop through all the child elements in between. Note that your code here doesn't have anything in between, so it's a little trivial; the docs you linked provide a better example.
I have never passed the state as props to SampleProvider component ..(I understood so. Maybe it's wrong)
You passed SampleProvider's state as a prop to Provider. Provider, in turn, passed its prop down to SampleConsumer.
I think the core of the misunderstanding here is your use (or naming) of SampleProvider. I'm not sure what you're trying to do with that state, but it's not really a "Provider" anymore and makes things confusing. This is unlike your SampleConsumer, which is still the default Consumer, just renamed.