Send props between Components (no related) React-Native - react-native

I have Components directory, there is js file Timer where I have countdown Component
const [countdownTimer, setCountdownTimer] = useState(15);
This component only returns <Text>{countdownTimer}</Text> on screen.
I also have another component Description. I want to handle this state in my Description component to make some changes after time has changed. The components aren't related (they aren't imported in each other)
I tried to import Description in Timer to send value as a props like
<Description setCountdownTimer={setCountdownTimer} />
and with style hide it but display: none isn't working on Android. I also try to just hide with another method
{false && <Description setCountdownTimer={setCountdownTimer} />}
but it's also not working, I got "undefined" in console.

For your case you should take a look at React Context: https://reactjs.org/docs/context.html

Hi #Danny If I understood your question correctly, you are trying to share the countDown state between two different components, and the way you try to do it may complicate you a bit, if not I suggest you use redux which is a library designed in order to manage the global states of applications, with redux you will be able to share the states of your application with several components.
You should need to create reducers and thanks to the createStore method from `redux you will be able to use a global state to your entire application
Here it's an example of code you can improve depending on your need :
import { createStore } from 'redux';
import reducer from './reducer';
import { Provider } from 'react-redux';
const store = createStore(reducer);
export default function App () {
return (
<Provider store = {store}>
<YourMainComponent />
</Provider>
)
}
You just need to wrapp your main component with the Provider component from 'react-redux' to access to your global state and manage it as you want. See more here
https://react-redux.js.org/introduction/basic-tutorial

Related

How to reload a component or call a function after action in another component with React Native

I use React Native and Expo to develop an application on mobile and tablet.
The objective is to be able to answer a questionnaire where several questions are divided into various categories. A question may have a category or not, so they don't really follow each other in the code.
I use a loop to display my categories, with its questions inside. Questions are components, categories too.
When I answer a question, sometimes I want to reload another question specifically (or several). After answering my question, I have a list of questions I want to reload.
I would like either to launch a function in the component, or to reload it entirely.
How do I reload the question component, which may be quite far from the one I acted on?
Thanks for your help !
I wanted to listen with UseEffect for the modification of my global variable, but it doesn't work. Also, I can't fully reload my page either. I would like to specifically reload the question component or run the function.
What I have already tried:
Reloading the page entirely from my screen with a function in global, didn't work (
I have a lot of elements so I would like to avoid reloading everything)
Listen with useEffect the change of my list of questions to modify to check if my id was in it, but the listening is not done
I can't send functions or other elements in the props of my question because they can be in different components (category or other) so too far away.
Question Component (simplified) :
export default function RealisationQuestionComponent(props){
//When action in Question A
function changeCheckA(value) {
[...]
if (props.question.questions_impactees !== undefined) {
global.questions_impactees = props.question.questions_impactees;
}
}
//Effect in Question B
useEffect(() => {
[my function or reload entire component]
}, [global.questions_impactees]);
return (
<>...</>
)
EDIT :
Following the answer, I tried to use useContext to retrieve my information, but it tells me Can't find variable : RealContext
What i would like to do :
https://www.w3schools.com/react/showreact.asp?filename=demo2_react_context2
What I have done :
My screen AuditRealisationScreen
const RealContext = createContext();
const [listIdVictimes, setListIdVictimes] = useState('please test');
[...]
return (
<RealContext.Provider value={listIdVictimes}>
<RealisationChapitreComponent/>
</RealContext.Provider>
)
RealisationChapitreComponent > [...] > RealisationQuestionComponent
In my component RealisationQuestionComponent
const listTest = useContext(RealContext);
[...]
return (
<Text> {listTest} </Text>
)
Can it work this way?
Use [contexts][1]. Using [reducers][2] with context would be more flexible and organised.
If you have a lot of states to manage with mess of siblings and parent-child and child-parent relations then using [Redux][3] would give you more control to manage those components and its states
What I used do for
How to reload a component or call a function after action in another
component with React Native
const context = ... // declare
and then
// import context
const App=()=>{
...
return(
<Context.Provider value={your functions, data, states, props whatever you want}>
{{ ...child components }}
<Context.Provider/>
)
}
You can play with these contexts usage to achieve your goal
[1]: https://reactjs.org/docs/hooks-reference.html#usecontext
[2]: https://reactjs.org/docs/hooks-reference.html#usereducer
[3]: https://redux.js.org/introduction/why-rtk-is-redux-today#what-is-redux

how to change element that fits a component to an element that fits a function in react native

I am a new react native developer, I found a component and I want to use it in a function, but it is not clear to me how I would change it, can I get a help?
Here is the component
import TagInput from 'react-native-tag-input';
...
<TagInput
value={this.state.emails}
onChange={(emails) => this.setState({ emails })}
labelExtractor={(email) => email}
text={this.state.text}
onChangeText={(text) => this.setState({ text })}
/>
I got the code from here https://bestofreactjs.com/repo/jwohlfert23-react-native-tag-input
I guess you are asking how to adapt the code to fit the functional component, which includes converting the this.setState.
React provides some thing called React hooks, which you can think of as a way to replace states and lifecycles. You can read more about it here here
In your case, it would go like this:
import { useState } from 'react';
...
// useState can only be called inside functional components
const [emails, setEmails] = useState([]);
const [text, setText] = useState('');
...
<TagInput
value={emails}
onChange={(emailTags) => setEmails(emailTags)} // to avoid naming confusion
labelExtractor={(email) => email}
text={text}
onChangeText={(inputText) => setText(inputText)}
/>
you don't need to convert the component itself, you can use it as it is, but you need to change its implementation.
Basically, if you want to use function components, which is highly recommended now, you need to change the usage of the state in the component which will contain the <TagInput>.
Instead of using "this" which points to the class itself, you need to implement a hook called useState.
You can find it the docs here: https://reactjs.org/docs/hooks-state.html

React Native - What's the best way to provide a global theme?

I've started using RN recently and have been doing some research on the implementation of themes and/or a dark-light mode. Here's roughly how I understand the two main options so far:
Context: Easy setup and can be accessed via hook inside the component that needs it. I count things like the React Navigation themes since that works, in essence, the same way(?)
Styled Components: Essentially just replacing the components with custom ones that access the current theme and that can then be set up to change their props on toggle if needed.
What I don't like about context, is that (the way I understand it) it wouldn't let me access the theme when using a StyleSheet, since that's outside the component. With the styled components on the other hands I'm not sure if I can cover all options inside my custom components, wouldn't I still need some sort of hook in each component anyway?
I was also thinking about just saving the current theme into my Store (in my case Zustand), together with an action that lets me toggle to a dark-mode. But so far, I haven't really seen anyone else do that, is there a downside to doing it that way?
It's not hard to pass context to your stylesheet, it just requires a bit of extra boilerplate. Something like the below:
import ThemeContext from '<path>';
export default () => {
const theme = useContext(ThemeContext);
const stylesWithTheme = styles(theme);
return <Text style={stylesWithTheme.text>Hi</Text>;
}
const styles = theme => StyleSheet.create({
text: {
color: themeStyles.color[theme];
}
});
const themeStyles = {
color: {
dark: '#FFF',
light: '#000',
},
};
I don't think using styled components would be a big departure from the above scheme.
If you did store your theme in state, and define your styles within the body of the component, that could be a savings in boilerplate. It's up to you whether having your styles in the component body is acceptable.
Side note, if you're already using a state manager, I would recommend not mixing it with the Context API without knowing more. It's simpler to have one solution there.

useFocusEffect hook is invoked even screen is in background when update global state on the screen in foreground

I am developing react-native project. This question is mainly about the useFocusEffect hook behaviour in my project.
I have several screens. There is a share data & each screen can update the data. So, I decided to use context to host the data via useState hook. When one screen setMyData(), the up-to-date data is available to all screens.
My data context to host shared data via useState hook:
import React, {useState} from 'react';
const MyDataContext = React.createContext();
export const MyDataProvider = ({children}) => {
const [myData, setMyData] = useState([]);
...
return (
<MyDataContext.Provider
value={{
myData,
setMyData,
}}>
{children}
</MyDataContext.Provider>
);
}
export default MyDataContext;
(My App component is wrapped by the MyDataContext.Provider, I just don't show that part here since it is not the point of my question)
In each of my screen components, I need to process my data once when the screen is on the foreground (visible), and update the global state with updated data. I use useFocusEffect hook. Something like below:
import {useFocusEffect} from '#react-navigation/native';
import MyDataContext from '../context/MyDataContext';
const MyScreenOne = ({navigation})=> {
const {myData, setMyData} = useContext(MyDataContext);
useFocusEffect(() => {
console.log('################# Screen one is FOCUSED! ');
const updatedData = processData([...myData]);
// set my data
setMyData(updatedData);
return () => {
console.log('Screen one was unfocused');
};
}, []);//empty array to force code in hook only run once
return (<View>
<MyButton onPress={()=> navigation.navigate("MyScreenTwo")}>
...
</View>
)
}
...
As you can see I have a button which navigates user to another screen. The other screen has the same structure of having that useFocusEffect hook in which it processes & updates data of global state.
When I run my app, the following happens to me:
At first MyScreenOne is launched. useFocusEffect is invoked, data is processed and updated and set to global state via the setMyData()
Since setMyData() is called in above step, the re-rendering happens, at this time, the useFocusEffect of MyScreenOne is not invoked again, which is good and expected.
Now I press the button which navigates to MyScreenTwo. Same process happens on MyScreenTwo: useFocusEffect is invoked, data is processed and updated and set to global state via the setMyData(). NOTICE: MyScreenOne is now not visible and in background stack/memory.
Since in above step the global state is updated by the second screen, re-rendering happens again to all screens in memory. This time surprisingly the useFocusEffect of MyScreenOne is invoked again, because of that the global state is updated again by the hook in MyScreenOne again, and re-rendering happens again to screens in memory.
As you can imaging , endless re-rendering happens now due to in above step the background screen MyScreenOne's useFocusEffect is invoked surprisingly.
Isn't useFocusEffect supposed to be run only when screen is visible? Why the useFocusEffect hook of background screen is also invoked when re-rendering happens? How to achieve what I need to only run the process data & update data once on each screen when the screen is visible in the meantime the data can be shared by all screens?
useFocusEffect doesn't take a dependency array. You need to pass useCallback as mentioned in the docs:
useFocusEffect(
React.useCallback(() => {
// whatever
}, [])
);
https://reactnavigation.org/docs/use-focus-effect/

Access Store on different screens in react-native

I am using a 'react-native-navigation' module for navigation in my app. I have declared my screens as below
import Screen1 from '../container/Screen1';
import Screen2 from '../container/Screen2';
const store = myStore();
Navigation.registerComponent('Screen1',() => Screen1,store,Provider);
Navigation.registerComponent('Screen2',() => Screen2,store,Provider);
Navigation.startSingleScreenApp({
screen:{
screen:'Screen1',
title:'Screen1',
navigatorStyle:{
navBarHidden:true
}
}
});
My challenge is to use store on different screens so that i can dispatch an action. Is there any way i can achieve that?
Note: myStore is declared in another file fulfilling all reducer, thunk configuration.
If I understand your question correctly, even though you pass store and Provider in registering each screen, you still just connect the components you want subscribed to the store and use Redux in the normal way. So:
export default connect(mapStateToProps, mapDispatchToProps)(Screen1)
I'm assuming because you tagged your question with react-redux that you understand the use of that library. If not, check out Usage with React.
You can use it using connect method below is sample demo
export default connect(mapStateToProps, mapDispatchToProps)(Screen1)
For some screen let say Screen2 if you not want to change value of store and only want to use store value then you can pass null as mapStateToProps
export default connect(null, mapDispatchToProps)(Screen2)
For some screen let say Screen3 if you want to change value(performing action) of store only but not want to display value then you can avoid passing mapDispatchToProps
export default connect(mapStateToProps)(Screen3)
sample code you can find here
https://github.com/rajscet/react_redux_basic