infinite Render in React - javascript

I am having problem figuring out why my application is doing endless render.
Inside, My stateful component, I am calling a redux action in componentDidMount method (calling componentWillMount also do endless render)
class cryptoTicker extends PureComponent {
componentDidMount() {
this.props.fetchCoin()
// This fetches some 1600 crypto coins data,Redux action link for the same in end
}
render() {
return (
<ScrollView>
<Header />
<View>
<FlatList
data={this.state.searchCoin ? this.displaySearchCrypto : this.props.cryptoLoaded}
style={{ flex: 1 }}
extraData={[this.displaySearchCrypto, this.props.cryptoLoaded]}
keyExtractor={item => item.short}
initialNumToRender={50}
windowSize={21}
removeClippedSubviews={true}
renderItem={({ item, index }) => (
<CoinCard
key={item["short"]}
/>
)}
/>
</View>
</ScrollView>
)
}
}
In CoinCard I am literally doing nothing besides this (Notice CoinCard inside Flat list)
class CoinCard extends Component {
render () {
console.log("Inside rende here")
return (
<View> <Text> Text </Text> </View>
)
}
}
Now, When I console log in my coincard render, I can see infinite log of Inside rende here
[Question:] Can anyone please help me figure out why this could be happening?
You can click here to see my actions and click here to see my reducer.
[Update:] My repository is here if you want to clone and see it by yourself.
[Update: 2]: I have pushed the above shared code on github and it will still log endless console.log statements (if you can clone, run and move back to this commit ).
[Update:3]: I am no longer using <ScrollView /> in <FlatList /> also when I mean endless render, I mean is that it is endless (& Unecessarily) passing same props to child component (<Coincard />), if I use PureComponent, it won't log endlessly in render () { but in componentWillRecieveProps, If I do console.log(nextProps), I can see the same log passed over and over again

There are some points to note in your code.
The CoinCard Component must be a PureComponent, which will not re-render if the props are shallow-equal.
You should not render your Flatlist inside the ScrollView component, which would make the component render all components inside it at once which may cause more looping between the Flatlist and ScrollView.
You can also a definite height to the rendered component to reduce the number of times component is rendered for other props.
Another thing to note is, only props in the component are rendered on scroll bottom, based on the log statement mentioned below.
import {Dimensions} from 'react-native'
const {width, height} = Dimensions.get('window)
class CoinCard extends React.PureComponent {
render () {
console.log(this.props.item.long) //... Check the prop changes here, pass the item prop in parent Flatlist. This logs component prop changes which will show that same items are not being re-rendered but new items are being called.
return (
<View style={{height / 10, width}}> //... Render 10 items on the screen
<Text>
Text
</Text>
</View>
)
}
}
UPDATE
This extra logging is due to the props being from the Flatlist to your component without PureComponent shallow comparison.
Note that componentWillReceiveProps() is deprecated and you should avoid them in your code.
React.PureComponent works under the hood and uses shouldComponentUpdate to use shallow comparison between the current and updated props. Therefore log console.log(this.props.item.long) in your PureComponent' render will log the unique list which can be checked.

Like izb mentions, the root cause of the pb is the business call that is done on a pure component whereas it is just loaded. It is because your component make a business decision (<=>"I decide when something must be showed in myself"). It is not a good practice in React, even less when you use redux. The component must be as stupid a possible and not even decide what to do and when to do it.
As I see in your project, you don't deal correctly with component and container concept. You should not have any logic in your container, as it should simply be a wrapper of a stupid pure component. Like this:
import { connect, Dispatch } from "react-redux";
import { push, RouterAction, RouterState } from "react-router-redux";
import ApplicationBarComponent from "../components/ApplicationBar";
export function mapStateToProps({ routing }: { routing: RouterState }) {
return routing;
}
export function mapDispatchToProps(dispatch: Dispatch<RouterAction>) {
return {
navigate: (payload: string) => dispatch(push(payload)),
};
}
const tmp = connect(mapStateToProps, mapDispatchToProps);
export default tmp(ApplicationBarComponent);
and the matching component:
import AppBar from '#material-ui/core/AppBar';
import IconButton from '#material-ui/core/IconButton';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import { StyleRules, Theme, withStyles, WithStyles } from '#material-ui/core/styles';
import Tab from '#material-ui/core/Tab';
import Tabs from '#material-ui/core/Tabs';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import AccountCircle from '#material-ui/icons/AccountCircle';
import MenuIcon from '#material-ui/icons/Menu';
import autobind from "autobind-decorator";
import * as React from "react";
import { push, RouterState } from "react-router-redux";
const styles = (theme: Theme): StyleRules => ({
flex: {
flex: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
root: {
backgroundColor: theme.palette.background.paper,
flexGrow: 1
},
});
export interface IProps extends RouterState, WithStyles {
navigate: typeof push;
}
#autobind
class ApplicationBar extends React.PureComponent<IProps, { anchorEl: HTMLInputElement | undefined }> {
constructor(props: any) {
super(props);
this.state = { anchorEl: undefined };
}
public render() {
const auth = true;
const { classes } = this.props;
const menuOpened = !!this.state.anchorEl;
return (
<div className={classes.root}>
<AppBar position="fixed" color="primary">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
Title
</Typography>
<Tabs value={this.getPathName()} onChange={this.handleNavigate} >
{/* <Tabs value="/"> */}
<Tab label="Counter 1" value="/counter1" />
<Tab label="Counter 2" value="/counter2" />
<Tab label="Register" value="/register" />
<Tab label="Forecast" value="/forecast" />
</Tabs>
{auth && (
<div>
<IconButton
aria-owns={menuOpened ? 'menu-appbar' : undefined}
aria-haspopup="true"
onClick={this.handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={this.state.anchorEl}
anchorOrigin={{
horizontal: 'right',
vertical: 'top',
}}
transformOrigin={{
horizontal: 'right',
vertical: 'top',
}}
open={menuOpened}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
</Menu>
</div>
)}
</Toolbar>
</AppBar>
</div >
);
}
private getPathName(): string {
if (!this.props.location) {
return "/counter1";
}
return (this.props.location as { pathname: string }).pathname;
}
private handleNavigate(event: React.ChangeEvent<{}>, value: any) {
this.props.navigate(value as string);
}
private handleMenu(event: React.MouseEvent<HTMLInputElement>) {
this.setState({ anchorEl: event.currentTarget });
}
private handleClose() {
this.setState({ anchorEl: undefined });
}
}
export default withStyles(styles)(ApplicationBar);
Then you will tell me: "but where do I initiate the call that will fill my list?"
Well I see here that you use redux-thunk (I prefer redux observable... more complicated to learn but waaaaaaaaaaaaaaaaay more powerful), then this should be thunk that initiates the dispatch of this!
To summarize:
Components: the stupidest element that normally should have only the render method, and some other method handler to bubble up user events. This method only takes care of showing its properties to the user. Don't use the state unless you have a visual information that belongs only to this component (like the visibility of a popup for example). Anything that is showed or updated comes from above: a higher level component, or a container. It doesn't decide to update its own values. At best, it handles a user event on a subcomponent, then bubble up another event above, and... well maybe at some point, some new properties will be given back by its container!
Container: very stupid logic that consists in wrapping a top level component into redux for it to plug events to actions, and to plug some part of the store to properties
Redux thunk (or redux observable): it is the one that handles the whole user application logic. This guy is the only one who knows what to trigger and when. If a part of your front end must contain the complexity, it's this one!
Reducers: define how to organize the data in the store for it to be as easily usable as possible.
The store: ideally one per top level container, the only one that contains the data that must be showed to the user. Nobody else should.
If you follow these principles, you should never face any issue like "why the hell this is called twice? and... who made it? and why at this moment?"
Something else: if you use redux, use an immutability framework. Otherwise you may face issues as reducers must be pure functions. For this you can use a popular one immutable.js but not convenient at all. And the late ousider that is actually a killer: immer (made by the author or mobx).

It seems Jacob in the above comment has managed to make the component render only twice.
This will definitely cause double initial render (and would cause an infinite render if it wasn't a PureComponent):
componentDidUpdate() {
var updateCoinData;
if (!updateCoinData) { // <- this is always true
updateCoinData = [...this.props.cryptoLoaded];
this.setState({updateCoinData: true}); // <- this will trigger a re render since `this.state.updateCoinData` is not initially true
}
...
}
Link to the issue in your repository

Related

Invariant Violation: Element type is invalid in createMaterialTopTabNavigator()/MaterialTopTabView render method, React Native w/ React Navigation v5

I am seeing the following error when using createMaterialTopTabNavigator() in React Native with React Navigation v5:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check the render method of `MaterialTopTabView`.
The relevant code is as follows. I tried to delete anything extraneous and add ellipses as a placeholder, so apologies if I missed anything important.
Connect.js:
import React, { Component } from 'react';
import { ... } from 'react-native';
import globalStyles from '../Styles/global-styles.js';
import Sessions from './Sessions.js';
import ChatList from './ChatList.js';
import { NavigationContainer } from "#react-navigation/native";
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
const TopTabNav = createMaterialTopTabNavigator();
function GetTopTabNavigator() {
return (
<NavigationContainer>
<TopTabNav.Navigator tabBarOptions={{...}}>
<TopTabNav.Screen name="Chat" component={ChatList}/>
<TopTabNav.Screen name="Sessions" component={Sessions}/>
</TopTabNav.Navigator>
<NavigationContainer/>
);
};
class ConnectScreen extends Component {
static router = TopTabNav.router;
constructor(props) {
super(props);
this.state = {
...
};
}
...
render() {
...
return (
<SafeAreaView style={{...}}>
...
<View style={globalStyles.container}>
GetTopTabNavigator()
</View>
</SafeAreaView>
);
}
}
export default ConnectScreen;
Research (and the error code) indicates that this is likely an issue with the way that a component is being imported or exported. To this end, I've tried several things:
1. Putting the Top Tab Navigator in a separate file, then exporting it (both as default and not with the appropriate brackets {} in the import statement) — any combinations results in either this error or another, for which the solution is to switch back to this way.
2. Copying the exact code from the documentation (https://reactnavigation.org/docs/material-top-tab-navigator/), pasting it in ConnectTopTabNav.js, then importing it using
import ConnectTopTabNav from './ConnectTopTabNav';
ConnectTopTabNav, too, I tried exporting as default and not as default, with the above corresponding to the former (shown below). Here is the code for ConnectTopTabNav.js:
import * as React from 'react';
import { Text, View } from 'react-native';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createMaterialTopTabNavigator();
export default function TobTabNav() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
However, the same problem results in Connect.js regardless of whether I attempt to render the component as ConnectTopTabNav() or . I also tried putting the above code directly into Connect.js, to no avail.
3. Looking through the #react-navigation/material-top-tabs file structure for any import/export errors. Didn't find anything, which isn't too surprising.
4. Putting the navigator inside my App.js navigation structure in several fashions. Also a dead end.
5. Surrounding the navigator with the < NavigationContainer /> component, with the corresponding flag to indicate that it's independent of the main navigator. (Edit: I've added this to the code to reflect this change.)
The error has arisen since upgrading to #react-navigation version 5. In version 4, I was able to create the navigator within the createMaterialTopTabNavigator() method directly, and didn't see an error.
I am using version 5.4.2 of #react-navigation/native and version 5.2.16 #react-navigation/material-top-tabs, on React Native v0.61.5. Appreciate any insight anyone can provide — I just don't see where else there's room for an error here. Please let me know if you need any other information. Thanks for your time!
Update: the solution was ultimately to update the version of react-native-tab-view, which #react-navigation/material-top-tabs is dependent upon. With the latest react-native-tab-view version, 2.15.1, and version 5.2.16 of #react-navigation/material-top-tabs, my navigator is working as expected.
you should normally wrap your navigation components at the top level with the Navigation container and I don't see it on your code sample. You should have something like this:
import { NavigationContainer } from "#react-navigation/native";
// Your other imports
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>

React: Spring transition not behaving properly

I recently got started with both React and JavaScript. I've been reading the Spring API docs for the Transition component, and ended up with this piece of code when doing some tests. Now, I expected a smooth transition, but got the following sequence:
When switch changes, the mounted element abruptly appears.
Some time goes by (this is dependent on the config that I choose)
The one unmounted disappears (abruptly as well)
For what I read in the docs, I'm not able to see what I'm doing wrong here, so any help is more than welcome. I've tested different configs and always get that sequence.
PS: Content is just a plain div that takes its background color as prop, so nothing fancy there.
import React from 'react';
import './App.css';
import Content from './components/content';
import {Transition, config} from 'react-spring/renderprops';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
switch: false
};
}
render() {
return (
<div id="container" onClick={() => {this.setState({switch: !this.state.switch})}}>
<Transition
config={config.slow}
items={this.state.switch}
from={{opacity: 0}}
enter={{opacity: 1}}
leave={{opacity: 0}}>
{s => s ? () => <Content backgroundColor="rgb(37, 95, 142)"></Content>
: () => <Content backgroundColor="rgb(37, 142, 118)"></Content>}
</Transition>
</div>
);
}
}
export default App;
Thanks!
The Transtition changes the opacity in your example, but you never give the changed values to you rendered component. It missing the prop parameter in the arrow function. You should add this prop to the style property to your component.
For example:
props => (<Content props={props} backgroundColor="rgb(37, 95, 142)" />)
And the Component is something like this:
const Content = ({ backgroundColor, props }) => (
<animated.div style={{ backgroundColor, ...props }}>Content</animated.div>
);
And now you can see the opacity change.
I also used animated.div here and added the native poperty to Transition for better performance.
Here is my example:
https://codesandbox.io/s/ecstatic-wood-7p1ym?file=/src/App.js

How do I access react-navigation from inside a component that isn't the HomeScreen?

I'm building a React Native app. I have imported createStackNavigator from react-navigation. I'm able to get it working on my Home screen - I click a button, it brings me to a new component. This is the code that I'm using to bring it into my Home.js
// src/components/Home/Home
export class Home extends Component {
render() {
return (
<React.Fragment>
<Button
title="Test button"
onPress={() => this.props.navigation.navigate('Roads')}
/>
<StatusBar />
<Header />
<Menu />
</React.Fragment>
);
}
}
const RootStack = createStackNavigator(
{
Home: Home,
Roads: Roads,
},
{
initialRouteName: 'Home',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
My Home page takes in a Menu which has a list of MenuItems. I am trying to get the MenuItems to jump to the appropriate pages. When I try to bring in the navigation inside MenuItem.js's render method, like so:
// src/components/Roads/Roads
render() {
const { navigate } = this.props.navigation;
console.log(this.props, "props is here");
I get the following error message:
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate').
Do I need to pass the navigator down in props to Menu.js and then to MenuItem.js? The docs give examples but it seems to be examples that assume you jam all your code into one file rather than across several components.
Have I set this up correctly?
When using a Navigator from react-navigation only the components you declare as Screens inherit the navigation prop (in your case Home and Roads)
This means that you will need to pass it as a prop to its children as you said:
<Menu navigation={this.props.navigation} />
<MenuItem navigation={this.props.navigation} />
In case anyone is wondering how to navigate from a component that isn't inside a Navigator then I suggest reading this part of the react-navigation documentation
https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

Not returning a component on button press in React-Native

I am a beginner in the react-native framework. I am building an sample mobile application. And I am stuck at the very basic step.
I am trying to call 'getBusinessNews()' function on click event, which will return a component. But due to some reason, it's not returning.
I have doubled checked the path of the component and its correct.
Even the console.log defined inside the function is getting displayed.
I am attaching the code, all kind of help is appreciated.
Thank you in advance.
import React, {Component} from 'react';
import {Text,View,TouchableOpacity} from 'react-native';
import BusinessNews from '../News/BusinessNews';
class categories extends Component{
render(){
return(
<View>
<TouchableOpacity onPress={this.getBusinessNews.bind(this)}>
<Text>Business News</Text>
</TouchableOpacity>
</View>
);
}
getBusinessNews(){
console.log(1);
return(
<BusinessNews />
);
}
export default categories;
Returning component from event handler/listener to render will not work.
Instead do state update to decide whether component BusinessNews will render or not.
Its should do like this.
constructor
constructor() {
this.state = {
showBusiness: false//initially set to false
}
}
getBusinessNews
getBusinessNews() {
this.setState({showBusiness: true})//set to true to show BusinessNews
}
render
render() {
render() {
return (
<View>
<TouchableOpacity
onPress={this
.getBusinessNews
.bind(this)}>
{this.state.showBusiness ===true && <BusinessNews/>}//check boolean true
<Text>Business News</Text>
</TouchableOpacity>
</View>
);
}
}
You can return a component on click. As you have to returns component in render() only. You need to change the logic to render component.
You can call <BusinessNews /> in somewhere in render() to add component.

React Context and separate classes

I've given up hope on getting mt head around Redux (I'm new to React), and see the Alpha version of React offers a new Context.
So I am attempting to learn it, and my goal is, I have a Navbar, which I want to respond to a state within my context, {isAuthorised: false}.
I'm following this guys video:
But he has all is code in a single file. I'm trying to do it 'right'.
What I did was created a folder called 'context' and within that, created a jsx called provider.jsx.
import React, {Component} from 'react';
export default class MyProvider extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
}
}
render() {
const MyContext = React.createContext();
return(
<MyContext.Provider value="Test Text">
{this.props.children}
</MyContext.Provider>
)
}
}
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/context/provider.jsx
In there, I created the context within the render (This might be wrong... maybe that's meant to happen in my App jsx?).
I create a state in there, defaulting isAuthenticated to false. (I'll add code later to set that to what it should be).
This compiles... and runs.
In my App component, I use my provider like this:
import MyProvider from './context/provider.jsx';
export default class App extends Component {
render() {
return (
<MyProvider>
<div>
<Router>
<div>
<Navbar />
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/app.jsx
So I am wrapping all my code with MyProvider.
In my Navbar component, I import my provider:
import MyProvider from '../../context/provider.jsx';
I then try and output somethign from my provider within my render:
return (
<div>
<MyProvider.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyProvider.Consumer>
<nav className="navbar navbar-expand">
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/components/navbar/navbar.jsx
But this goes very badly for me.
Warning: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in, or you might have mixed up
default and named imports.
Check the render method of Navbar.
in Navbar (created by App)
in div (created by App)
And
Uncaught Error: Element type is invalid: expected a string (for
built-in components) or a class/function (for composite components)
but got: undefined. You likely forgot to export your component from
the file it's defined in, or you might have mixed up default and named
imports.
How can I get this to work? Where should my .createContext reside?
Code (With error) is here.
So the problem is that you export MyProvider and try to access static component on it - which is undefined:
console.log(MyProvider.Consumer); // undefined
the Consumer is existing as a static property only in MyContext component.
What you need to change:
provider.jsx
import React, {Component} from 'react';
export const MyContext = React.createContext();
export default class MyProvider extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
}
}
render() {
return(
<MyContext.Provider value={this.state.isAuthenticated}>
{this.props.children}
</MyContext.Provider>
)
}
}
then in navbar.jsx
import MyProvider, { MyContext } from '../../context/provider.jsx';
<MyProvider>
<MyContext.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyContext.Consumer>
</MyProvider>
take a look at this tutorial.
EDIT:
To have the Consumer exist in MyProvider you would have to assign static variable on it that points to MyContext Consumer
MyProvider.Consumer = MyContext.Consumer;
Then I think you could use it like:
<MyProvider>
<MyProvider.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyProvider.Consumer>
</MyProvider>
However I'm not sure if it is a good idea.
Was getting the same error...
Turns out I was using an older version of react-dom. Updating it to ^16.3.0 fixed it for me!
Thanks to this video I was able to get it working. Here's my solution...
AuthCtrProvider.js
import React, { Component } from 'react';
// create context blank, it gets filled by provider
export const MyContext = React.createContext();
// the state object is initially in the AuthCtrProvider and gets passed into the context
// via the value argument to the provider
export default class AuthCtrProvider extends Component {
state = {
isAuthenticated: false,
counter: 100,
doubl: () => { this.setState({ counter: this.state.counter * 2 } ) }
}
render() {
return (
// pass in this.state (which carries the data and the doubl func and also
// pass in three additional functions
<MyContext.Provider value={{
state: this.state,
toggle: () => { this.setState({ isAuthenticated: !this.isAuthenticated })},
incr: () => { this.setState({ counter: this.state.counter + 1 })},
decr: () => { this.setState({ counter: this.state.counter - 1 })}
}
}>
// include the children that will be wrapped by this provider (in App.js)
{this.props.children}
</MyContext.Provider>
)
}
}
We export the MyContext and the default AuthCtrProvider. This is probably bad form here because I'm mixing a counter with an unrelated isAuthenticated. I'm just doing this to demo the functionality.
Also note - there's a function doubl in the state and there's functions in the provider that are separate from the state. Again, this is only used to make a point further down.
App.js
import React, { Component } from 'react';
import AuthCtrProvider, { MyContext } from './AuthCtrProvider';
class App extends Component {
render() {
return (
<div className="App">
<Navigation />
<AuthCtrProvider>
<MyContext.Consumer>
{(context) => (
<p>Counter from the context = {context.state.counter}</p>
)}
</MyContext.Consumer>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<Main />
</AuthCtrProvider>
</div>
);
}
}
This shows the counter from the context.state so we can see it at the top level. In the project I have other imports for navigation and routing. One of my pages that loads in is ProjectDetails.jsx...
ProjectDetails.jsx
import React from 'react';
// in this file I only need to import the context
import { MyContext } from '../AuthCtrProvider';
// other imports for presentation components, OData, and such
render() {
return (
<div style={{ display: "flex", flex: "1 1 0", alignItems: "flex-start", overflowY: "auto" }}>
// we get access to the context using 'context' var but it can be whatever name you want
<MyContext.Consumer>
{context => (
<React.Fragment>
// note accessing the 'incr' function which is outside the state so it's just context.incr
<button onClick={context.incr}>incr {context.state.counter}</button>
// note access the 'doubl' function inside the state, hence context.state.doubl
<button onClick={context.state.doubl}>dubl {context.state.counter}</button>
</React.Fragment>
)}
</MyContext.Consumer>
// other presentation going here
</div>
);
}
That's it. Context and provider in a separate file, data and functions accessible from other files.
HTH, Mike

Categories

Resources