const displayNameRef = useRef('');
useEffect(() => {
(async () => {
const loginMethod = await AsyncStorage.getItem('login-method');
if (loginMethod === 'google') {
displayNameRef.current = await AsyncStorage.getItem('google-user-name');
setState((s) => s + 1);
} else {
displayNameRef.current = 'Randomly_generated';
}
})();
}, []);
this is my useffect, here i getitem(display name )from async storage but i want to convert all the hooks into class component
<Header
title={('hi', displayNameRef.current)}
setSelectedTab={this.setSelectedTab}
selectedTab={this.state.selectedTab}
navigation={this.props.navigation}
openDrawerPanel={this.openDrawerPanel}
/>
so here i want to display displayNameRef.current inside of header
If you want to turn your hooks into class component, try to process à below:
class SomeCalss extends React.Component {
constructor(props) {
super(props);
this.state = {
s: 0
}
this.displayNameRef = React.createRef();
}
async componentDidMount() {
const loginMethod = await AsyncStorage.getItem('login-method');
if (loginMethod === 'google') {
displayNameRef.current = await AsyncStorage.getItem('google-user-name');
this.setState({s: this.state.s + 1});
} else {
displayNameRef.current = 'Randomly_generated';
}
}
render() {
return <Header
title={('hi', this.displayNameRef.current)}
setSelectedTab={this.setSelectedTab}
selectedTab={this.state.selectedTab}
navigation={this.props.navigation}
openDrawerPanel={this.openDrawerPanel}
/>
}
}
But you have to be aware that displayNameRef.current = 'Randomly_generated'; doesn't trigger re-render
I have an App with a navigationbar with 2 Screens.
When i apply a function on Screen/Component 1 , I want to render or trigger a change in the Second Screen.
is there a way to either re-render the screen on Enter or to update the state of the other screen ?
Component one:
export default class HomeScreen extends React.Component {
constructor() {
super();
}
_onPress(){
try {
await AsyncStorage.setItem('value', 'changed Value');
} catch (error) {
console.log(error.message);
}
console.log("saved: " + this.state.userName )
}
render() {
return (
<View style={styles.container}>
<Button title="btn" onPress={() => this._onPress()} >
</Button>
</View>
)
}
component 2:
export default class SecondScreen extends React.Component {
constructor() {
super();
this.state = {some : ''}
}
async getValue () {
let recievedValue = '';
try {
let promise = await AsyncStorage.getItem('value') || 'cheeseCake';
promise.then((value) => recievedValue = value)
} catch (error) {
// Error retrieving data
console.log(error.message);
}
return recievedValue
}
render() {
var value= this.getValue();
return (
<View style={styles.container}>
<Text>
HERE CHANGED VALUE: {value}
</Text>
<Button onPress={()=> this.setState((prev)=> {some:'Thing'})}>
</Button>
</View>
)
}
When i press the Button on screen 1(HomeScreen) the value is saved.
But it only shows in the secont screen when I trigger a statechange via Button Press.
How do I render the screen when I visit the screen via navigation bar ?
Did you try EventEmiter?
Use this custom event listener: https://github.com/meinto/react-native-event-listeners
eg:
import { EventRegister } from 'react-native-event-listeners'
/*
* RECEIVER COMPONENT
*/
class Receiver extends PureComponent {
constructor(props) {
super(props)
this.state = {
data: 'no data',
}
}
componentWillMount() {
this.listener = EventRegister.addEventListener('myCustomEvent', (data) => {
this.setState({
data,
})
})
}
componentWillUnmount() {
EventRegister.removeEventListener(this.listener)
}
render() {
return <Text>{this.state.data}</Text>
}
}
/*
* SENDER COMPONENT
*/
const Sender = (props) => (
<TouchableHighlight
onPress={() => {
EventRegister.emit('myCustomEvent', 'it works!!!')
})
><Text>Send Event</Text></TouchableHighlight>
)
let say I have a state like this:
constructor(props) {
super(props);
this.state = {
FirstTime:
{
foo: 'ex1'
}
}
}
and then I setState the FirstTime to add another key/value:
this.setState({FirstTime: {...this.state.FirstTime, bar: 'ex2'}})
there's a way to change the initial state to be like this:
constructor(props) {
super(props);
this.state = {
FirstTime:
{
foo: 'ex1',
bar: 'ex2'
}
}
}
when I reloaded the apps?
Try something like this
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
FirstTime: {
foo: 'ex1'
}
}
}
render() {
console.log(this.state.FirstTime); //Sorry a typo found in this line
return (
<div>Hey</div>
);
}
componentDidMount() {
let obj = {
bar: 'ex2'
}
let finalData = { ...this.state.FirstTime, ...obj }
this.setState({ FirstTime: finalData })
}
}
const rootElement = document.getElementById("root")
ReactDOM.render(
<App />,
rootElement
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
How can a component be moved from one part of the render hierarchy to another while maintaining component state? In the example below, the result of the call to setView creates a new view (as seen by a new instanceValue number), even though I pass what looks like the existing view.
class TestTo extends React.Component {
constructor(props) {
super(props);
this.state = {
instanceValue: parseInt(Math.random() * 100)
}
}
render() {
return <Text>{this.state.instanceValue}</Text>
}
}
class TestFrom extends React.Component {
constructor(props) {
super(props);
this.state = {
view: <TestTo />
}
}
doSet = () => {
this.props.nav.setView(this.state.view);
}
render() {
return <View>
<Button title="doaction" onPress={this.doSet} />
{this.state.view}
</View>
}
}
class Holder extends React.Component {
constructor(props) {
super(props);
this.state = {
view: <TestFrom nav={this} />
}
}
setView = (view) => {
this.setState({view: view});
}
render() {
return this.state.view
}
}
<Holder />
I use react-navigation for manage routes. This is my Home component:
class HomeScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: {
firstname: 'John',
avatar: 'john-profile.png',
location: 'Canada',
}
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
render() {
return (
<View>
<Image src="{this.state.userProfile.avatar}" />
<Text>Firstname: {this.state.userProfile.firstname}</Text>
<Text>Location: {this.state.userProfile.location}</Text>
</View>
);
}
}
And this is the Profile screen:
class ProfileScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: null,
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
save() {
var userSavedProfile = this.state.userProfile;
userSavedProfile.firstname = "Peter";
userSavedProfile.avatar = "peter-avatar.png";
userSavedProfile.location = "EEUU";
this.setState({userProfile: userSavedProfile});
AsyncStorage.setItem('userProfile', JSON.stringify(this.state.userProfile), () => {});
}
render() {
return (
<View>
<Button title="Save" onPress={() => this.save()} />
</View>
);
}
}
When I save the new user information and I press back button in header (react-navigation) the user profile is old, firstname = John, etc... How update state from Home when user press back button and refresh data?
You can use BackHandler from react-native
https://facebook.github.io/react-native/docs/backhandler.html
You can change state inside function of backhandler
I think that your application would need a state manager, where you could store your user information and access it anywhere in the app. You should take a look at Redux. It would fit your needs and the info in your Home screen would automatically update.
but for anyone who will need this functionality in there react native application here is the solution you can try.
using react navigation.
import {withNavigationFocus} from "react-navigation";
class Profile extends Component {
...
}
export default withNavigationFocus(Profile);
There can be two workarounds check it out -
1 Send callback in params
class HomeScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: {
firstname: 'John',
avatar: 'john-profile.png',
location: 'Canada',
}
}
this.getUserData = this.getUserData.bind(this);
}
componentDidMount() {
this.getUserData;
}
getUserData = () =>{
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
render() {
return (
<View>
<Image src="{this.state.userProfile.avatar}" />
<Text onPress={()=>this.props.navigation.navigate('ProfileScreen', this.getUserData)}>Firstname: {this.state.userProfile.firstname}</Text>
<Text>Location: {this.state.userProfile.location}</Text>
</View>
);
}
}
class ProfileScreen extends React.Component {
constructor(props) {
this.state = {
userProfile: null,
}
}
componentDidMount() {
AsyncStorage.getItem('userProfile', (errs, result) => {
this.setState({userProfile: JSON.parse(result)});
});
}
save() {
var userSavedProfile = this.state.userProfile;
userSavedProfile.firstname = "Peter";
userSavedProfile.avatar = "peter-avatar.png";
userSavedProfile.location = "EEUU";
this.setState({userProfile: userSavedProfile});
AsyncStorage.setItem('userProfile', JSON.stringify(this.state.userProfile), () => {});
//this is the magic
this.props.navigation.state.params.getUserData();
}
render() {
return (
<View>
<Button title="Save" onPress={() => this.save()} />
</View>
);
}
}
2 On HomeScreen Constructor add this (Dirty one)
this.props.navigation.addListener(
'didFocus',
payload => {
this.setState({is_updated:true});
}
);
You can use componentDidUpdate(){...} insted componentDidMount(){}