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

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>
);
};

Related

Setting value for React context values with React testing library

I am working on testing a component using react-testing-library. The component has an alert which accepts a prop that comes from context to determine whether the alert is open or not.
const PersonRecord = () => {
const {
personSuccessAlert,
setPersonSuccessAlert,
updatePersonSuccessAlert,
setUpdatePersonSuccessAlert,
} = useContext(PeopleContext);
return (
{personSuccessAlert && (
<div className="person-alert-container">
<Alert
ariaLabel="person-create-success-alert"
icon="success"
open={personSuccessAlert}
/>
</div>
)}
)
}
So the above code uses context to pull the value of personSuccessAlert from PeopleContext. If personSuccessAlert is true the alert will display. My context file is set up as follows:
import React, { createContext, useState } from 'react';
export const PeopleContext = createContext();
const PeopleContextProvider = ({ children }) => {
const [personSuccessAlert, setPersonSuccessAlert] = useState(false);
const [updatePersonSuccessAlert, setUpdatePersonSuccessAlert] = useState(
false,
);
return (
<PeopleContext.Provider
value={{
personSuccessAlert,
updatePersonSuccessAlert,
setPersonSuccessAlert,
setUpdatePersonSuccessAlert,
}}>
{children}
</PeopleContext.Provider>
);
};
export default PeopleContextProvider;
Now I am trying to develop a test which passes personSuccessAlert = true to the PersonRecord component.
Here is what I have been trying:
export function renderWithEmptyPerson(
ui,
{
providerProps,
path = '/',
route = '/',
history = createMemoryHistory({ initialEntries: [route] }),
},
) {
return {
...render(
<MockedProvider mocks={getEmptyPerson} addTypename={false}>
<PeopleContextProvider {...providerProps}>
<Router history={history}>
<Route path={path} component={ui} />
</Router>
</PeopleContextProvider>
</MockedProvider>,
),
};
}
describe('empty person record rendering', () => {
afterEach(cleanup);
test('empty person', async () => {
const providerProps = { value: true };
const { getByText, queryByText, queryByLabelText } = renderWithEmptyPerson(
PersonRecord,
{
providerProps,
route: 'people/6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
path: 'people/:slug',
},
);
expect(getByText('Loading...')).toBeInTheDocument();
});
});
I have tried different variations of const providerProps = { value: true };. Replacing value with personSuccessAlert did not work.
Any advice or help is appreciated.
You are passing providerProps to the PeopleContextProvider, but the PeopleContextProvider is not doing anything with the props. You'll need to actually use those props, for example to set the initial state. You could try something like:
const PeopleContextProvider = ({ children, initialPersonSuccessAlert = false }) => {
const [personSuccessAlert, setPersonSuccessAlert] = useState(initialPersonSuccessAlert);
const [updatePersonSuccessAlert, setUpdatePersonSuccessAlert] = useState(
false,
);
return (
<PeopleContext.Provider
value={{
personSuccessAlert,
updatePersonSuccessAlert,
setPersonSuccessAlert,
setUpdatePersonSuccessAlert,
}}>
{children}
</PeopleContext.Provider>
);
};
This would allow you to set the initial state of personSuccessAlert by passing in a initialPersonSuccessAlert prop. You could update your test like so:
const providerProps = { initialPersonSuccessAlert: true };
Alternatively, if you only wanted to make changes in your test file, you could consider updating the renderWithEmptyPerson function to use PeopleContext.Provider directly instead of the PeopleContextProvider component. That will allow you to set the context value however you like.

How to get the React context from another context?

I have two contexts - gameContext, roundContext. I am using useReducer to manipulate the state. Can I dispatch action in gameContext from roundContext reducer (RoundReducer)?
The reducer function is defined outside RoundProvider component.
const RoundReducer = (state: RoundStateType, action: any) => {
///sth
}
const RoundProvider: React.FC<{}> = ({ children }) => {
const [state, dispatch] = useReducer(RoundReducer, initState);
return (
<RoundContext.Provider
value={{ roundState: state, roundDispatch: dispatch }}>
{children}
</RoundContext.Provider>
);
};
The GameProvider component looks the same.
If you have nested contexts GameContext and RoundContext you can access the outer game context from the inner round, then call a setter/dispatch method to initiate a change in each. The inner RoundContext provider is inside the GameContext provider, so there (dispatch in this example) you have access to the methods exposed by the GameContext.
const GameContext = React.createContext(null);
const GameProvider = ({ children }) => {
const [gameState, setGameState] = React.useState();
return (
<GameContext.Provider value={{ gameState, setGameState }}>
{children}
</GameContext.Provider>
);
};
const useGame = () => React.useContext(GameContext)
const RoundContext = React.createContext(null);
const RoundProvider = () => {
const { gameState, setGameState } = useGame();
const [roundState, setRoundState] = React.useState();
const dispatch = (value) => {
// Do something to both the round and the game state
setGameState(value.toUpperCase());
setRoundState(value);
};
return (
<RoundContext.Provider value={{ roundState, dispatch }}>
{children}
</RoundContext.Provider>
);
}
const useRound = () => React.useContext(RoundContext)
const Main = () => {
const game = useGame()
const round = useRound()
const handleAction = () => {
round.dispatch('some value that also goes to the game')
}
return <>
<input type='text' onChange={handleAction} />
<div>{game.gameState}</div>
<div>{round.roundState}</div>
</>
}
const App = () => (<GameProvider>
<RoundProvider>
<Main />
</RoundProvider>
</GameProvider>)
Here's a codesandbox example:
https://codesandbox.io/s/xenodochial-wind-gkhje
pass the prop from the game context to roundContext or other way around, let say if you're using react hooks - useState,in props pass the setValue.
Please review the following code.
also, this is just for referance
export default function GameComponent(){
//suppose this is parent component and you want to change the value from child componenet
const [value, setValue] = useState("Patel");
return(
<div>
<h1>{value}</h1>
<RoundComponent setValue={setValue} value={value} />
//pass props like this
</div>
)
}
now coming back to round component
export default function RoundComponent(props){
return(
<div>
<input type="text" name="name" value={props.value} onChange={e=>props.setValue(e.target.value)}/>
</div>
)
}
I hope this answers your question.

How to pass State with context Api react?

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>
)
}

Unexpected token '<' in React Context Provider

I'm trying to implement a language context in a React App, however when I try to pass some elements into the value prop, it won't work.
The error is: Unexepect token in line 2:2 (i.e.). But the tags are well closed. Am I missing something in value which is absolutely required?
const LanguageProvider = ({ children }) => (
<LanguageContext.Provider value={{
setLanguage,
translations
}}
>
{children}
</LanguageContext.Provider>
);
setLanguage comes from:
const [language, setLanguage] = useState('en_US');
and translations equals to an object of strings:
const translations = {
en_US: {
settings: {
menu: 'Main Menu',
screen: 'Screen'
}
},
es_MX: {
settings: {
menu: 'MenĂº Principal',
screen: 'Pantalla'
}
}
};
The tags are okay, you just need to move setLanguage into LanguageProvider.
const LanguageProvider = ({ children }) => {
const [language, setLanguage] = useState("en_US");
return (
<LanguageContext.Provider
value={{
setLanguage,
translations
}}
>
{children}
</LanguageContext.Provider>
);
};
I have a sandbox you can try.

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>
);
};

Resources