How to pass State with context Api react? - reactjs

First I created a .js file and created context.
In app.js
export default function App({ navigation }) {
const [ItemURL,setItemURL] = useState('URL')
return (
<ItemContext.Provider value={ItemURL}>
...
</ItemContext.Provider>
)
}
now I want to pass my setItemURL to my child component
So I tried.
export default const ItemsComponent = (props) => {
const [URL, setURL] = useContext(ItemContext)
return(
<TouchableWithoutFeedback
onPress={() => {
setURL(props.Json.Image)
}}
/>
)
}
but its not working and saying setURL is not a function(in setURL(props.Json.Image)) ,setURL is 'R'

You should actually pass the setURL function in the context value as well.
export default function App({ navigation }) {
const [ItemURL, setItemURL] = useState('URL');
const value = [ItemURL, setItemURL];
return (
<ItemContext.Provider value={value}>
...
</ItemContext.Provider>
)
}

Related

React Native - Getting values from useContext - issue with objects/functions

I've issues with setting and getting values from my Context provider. Code below works, I am getting the value "2" in my other screen through useContext(). But it only works when it's hardcoded as below.
export const PinfoContext = createContext({});
export const PinfoProvider = ({ children }) => {
const [px, setPx] = useState(null);
return (
<PinfoContext.Provider
value={{
px: 2,
setPx,
}}
>
{children}
</PinfoContext.Provider>
);
};
export default function Screen2({ route, navigation }) {
const { px } = useContext(PinfoContext);
return (
<View>
<Text>Test-- {px}</Text>
</View>
);
}
If I was to change my provider something like below; I cant seem to set/get "px" values to "aaa" from my provider. What would be the correct way to do this? Logic here is that I am going to get objects from my db and use it in my other screen.
export const PinfoContext = createContext({});
export const PinfoProvider = ({ children }) => {
const [px, setPx] = useState(null);
return (
<PinfoContext.Provider
value={{
px,
setPx,
function: () => {
setPx("aaa");
},
}}
>
{children}
</PinfoContext.Provider>
);
};

React Query - Client Provider in the _app.tsx using layouts [duplicate]

I have an auth context component where I'm wrapping my main app component, but at the same time I'm also trying to do page specific layout component per Next.js documentation here: https://nextjs.org/docs/basic-features/layouts#per-page-layouts
Am I doing this correctly, because I can't seem to be getting the data from my Context provider.
/context/AuthContext.js
const UserContext = createContext({});
export default function AuthContext({children}) {
// .. code
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
}
export const useUser = () => useContext(UserContext);
/_app.js
function MyApp({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page);
return getLayout(
<div>
<AuthContext>
<Component {...pageProps} />
</AuthContext>
</div>
);
}
export default MyApp;
/components/Project/List.js
import { useUser } from "../../context/AuthContext";
const ProjectList = () => {
const { user } = useUser();
console.log("get user data", user);
return (
<>
test
</>
);
};
export default ProjectList;
I'm trying to console log the user, but it's giving me undefined. I'm thinking it's because the way it's wrapped as a layout component? I could be doing this wrong. But I did console log inside my AuthContext for user, and the information there is correct.
/pages/projects/index.js
const Projects = () => {
// code goes here
return (
<div>
code goes here
</div>
)
}
export default Projects;
Projects.getLayout = function getLayout(page) {
return <ProjectLayout>{page}</ProjectLayout>;
};
When I remove the Projects.getLayout block of code, the data comes back, but when I add this code, data is gone.
/components/Project/Layout.js
const ProjectLayout = ({children}) => {
return (
<>
<ProjectList />
{children}
</>
}
export default ProjectLayout
With your current structure ProjectLayout isn't getting wrapped by the AuthContext, meaning you won't have access to its context.
You can modify your _app's structure and move the getLayout call around so that the context wraps it properly.
function MyApp({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page);
return (
<AuthContext>
{getLayout(<Component {...pageProps} />)}
</AuthContext>
);
}
Note that calling getLayout inside the Context could lead to errors if the getLayout function uses hooks or stuff that depends on a parent element.
It will be calling getLayout first and then the context, so the value of it will be initially the default (fallback) value (it's like doing foo(bar()) and expecting that foo will be called before bar).
To avoid this, return directly the component (using getLayout as a function that generates a component):
// /pages/projects/index.js
Projects.getLayout = (children) => (
// can't use hooks here, return the component immediately
<ProjectLayout>{children}</ProjectLayout>;
);
or use the layout as a component:
// /pages/projects/index.js
Projects.Layout = ({ children }) => {
return <ProjectLayout>{children}</ProjectLayout>;
};
// /pages/_app.js
export default function App({ Component, pageProps }) {
const Layout = Component.Layout || (({ children }) => children);
return (
<AuthContext>
<Layout>
<Component {...pageProps} />
</Layout>
</AuthContext>
);
}
Edit: The difference is more visible without JSX
// incorrect
return React.createElement(AuthContext, null,
// getLayout is called before AuthContext
getLayout(
React.createElement(Component, pageProps)
)
)
// correct
return React.createElement(AuthContext, null,
// Layout is called after AuthContext
React.createElement(Layout, null,
React.createElement(Component, pageProps)
)
)

React: Is there a way to access component state from function in another file?

I've a react component which includes a large function that updates the component state, the function is large so I want to move it to a separate file and export it in the react component. But I don't find anyway to access the component state if I move the function to its own file.
Is there anyway to do this ?
example:
component.tsx
import { myFunction } from './function.ts'
const [toggle, setToggle] = useState(false)
const my_component = () => {
return (
<div>
<button onClick={myFunction}>Run function</button>
</div>
)
}
export default my_component
function.ts
export const myFunction = () => {
// do something that updates `toggle`
}
you can do the logic apart from the component and return the result to the component. have a look at the code below.
https://codesandbox.io/s/hopeful-dubinsky-930p7?file=/src/App.js
This is just a raw example of what you can do with custom state hooks (reference: https://dev.to/spukas/react-hooks-creating-custom-state-hook-300c)
import React from 'react';
export function useMyFunction(value) {
const [toggle, setToggle] = React.useState(value || false);
const myFunction = () => {
// do something that updates `toggle` with setToggle(...)
}
return { toggle, myFunction };
}
import { useMyFunction } from './function.ts'
const my_component = () => {
const [toggle, myFunction] = useMyFunction(false)
return (
<div>
<button onClick={myFunction}>Run function</button>
</div>
)
}
export default my_component
This can be achieved by 2 different ways one using HOC components and another just by using functions.
Approach 1: Using HOC
handler.js
const withHandlers = (WrappedComponent) => {
class HandlerComponent extends Component {
state = {toggle:false};
myFunction = () => {
//Do your update here
}
render() {
return <WrappedComponent
toggle={this.state.toggle
myFunction={this.myFunction}
/>
}
};
my_component.js
const my_component = (props) => {
return (
<div>
<button onClick={props.myFunction}>Run function</button>
</div>
}
export default withHandlers(my_component);
Approach 2: Using Functions
handler.js
export const myFunction(toggle) => {
return !toggle; //return the changed value
}
my_component.js
const my_component = () => {
const [toggle, setToggle] = useState(false);
const myFunction = () => {
setToggle(handler.myFunction); //the state will be passed as a parameter by default
};
return(
<div>
<button onClick={myFunction}>Run function</button>
</div>
);
};
For the toggle to work, it must be passed to the function as a props then for update it used state management (redux or react context).
The best solution is to define the toggle in the function itself and pass it a Boolean props to control it.
import { myFunction } from './function.ts'
const my_component = () => {
return (
<div>
<button onClick={myFunction(false)}>Run function</button>
</div>
)
}
export default my_component
function.ts
export const myFunction = (props) => {
const [toggle, setToggle] = useState(props || false);
// your codes
};

React useContext value is not getting passed from the provider?

I'm trying to pass a value down using useContext as below
This is Context.js
export const selectedContext = React.createContext();
export const SelectProvider = () => {
return (
<selectedContext.Provider value={"Team One"}>
<Cards />
<Pies />
</selectedContext.Provider>
);
};
I'm calling the context in one of the components like so
This is in Card.js (a child in the provider)
const value = React.useContext(selectedContext);
console.log(value);
When I initialize the value from React.createContext, the value is passed down to my component but when I try using the provider it doesn't work.
What am I doing wrong?
When you are using React.useContext like this it's not wire into the <Context.Provider>
Please see the docs on who to use React.useContext here.
It's seems that the React.useContext will not work with in the Provider direct component children, so you need to make one more component in between. (like in the docs example)
const selectedContext = React.createContext();
const SelectProvider = () => {
return (
<selectedContext.Provider value={"Team One"}>
<Cards />
</selectedContext.Provider>
);
};
const Cards = () => {
const value = React.useContext(selectedContext);
console.log(value); // will not work
return (
<Card />
);
};
const Card = () => {
const value = React.useContext(selectedContext);
console.log(value); // will work
return (
<div>My Card</div>
);
};
If you need it to work on the first layer of component you can use <Context.Consumer> and it will work within.
const selectedContext = React.createContext();
const SelectProvider = () => {
return (
<selectedContext.Provider value={"Team One"}>
<Cards />
</selectedContext.Provider>
);
};
const Cards = () => {
const value = React.useContext(selectedContext);
console.log(value); // will not work
return (
<div>
<selectedContext.Consumer>
{({value}) => (
<h1>{value}</h1> // will work
)}
</selectedContext.Consumer>
</div>
);
};
Your code is fine, but you should "call the context" in the child component of the provider, as the value is available in Provider's children:
export const SelectedContext = React.createContext();
export const SelectProvider = ({ children }) => {
return (
<SelectedContext.Provider value={'Team One'}>
{children}
</SelectedContext.Provider>
);
};
const ProviderChecker = () => {
const value = React.useContext(SelectedContext);
return <div>{value}</div>;
};
const App = () => {
return (
<SelectProvider>
<ProviderChecker />
</SelectProvider>
);
};

How to change context value in functional component?

I have a context named StatusContext like this:
export const statusCtxInit = {
open: false,
toggleOpen() {
this.open = !this.open;
}
};
const StatusContext = React.createContext(statusCtxInit);
export default StatusContext
The whole app is wrapping with the provider:
// ...
<StatusContext.Provider value={statusCtxInit}>
// ...
To use the values of my context I use useContext in my FC and it works when I get the value.
function MyComp() {
const status = useContext(StatusContext);
return (
<div>
{status.open
? `It's Open`
: `It's Closed`}
<button onClick={() => status.toggleOpen()}>
Toggle
</button>
</div>
)
}
export default MyComp
On the other hand, I also want to change the context by calling the toggleOpen but, it does not work as I want. Actually the value changes but not effect the MyComp.
What I did wrong? What shall I do?
import React from 'react';
const statusContext = React.createContext();
const {Provider} = statusContext;
// custom provider
export const StatusProvider = ({children}) => {
const [isOpen, setOpen] = React.useState(false)
const toggle = () => setOpen(v => !v)
return (
<Provider value={{isOpen, toggle}}>
{children}
</Provider>
)
}
//custom hook
export const useStatus = () => React.useContext(StatusContext)
//usage
function MyComp() {
const status = useStatus()
return (
<div>
{status.isOpen
? `It's Open`
: `It's Closed`}
<button onClick={() => status.toggle()}>
Toggle
</button>
</div>
)
}
export default MyComp

Resources