Hello everyone and thank you for reading,
I'm new to redux and Iv been trying to connect a grandchild component with the store, but for some reason It doesn't work.
The child component (called canvas) uses the store as well and doesn't show any problem, but when I'm trying to get the same data in a component I call from within the child component I get: "Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a Provider tag"
I searched for the solution on the internet and everybody suggests to wrap the app component in provider tags inside index.js, but I already did that in the beginning
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {createStore} from 'redux';
import allReducer from './reducers'
import { Provider } from 'react-redux';
const store = createStore(allReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
// <React.StrictMode>
<Provider store={store}>
<App/>
</Provider>,
//</React.StrictMode>,
document.getElementById('root')
);
App.js
import React from 'react';
import "./App.css";
import { Canvas } from "./components/Canvas";
export default function App() {
return (
<div className="main-div">
<Canvas/>
</div>
);
}
relevant data from canvas.js (child component)
import { Stage, Layer, Rect } from 'react-konva';
.
.
.
.
const theTextObjs = TextObjs.map((text,key) => {
return (
<TextBox
//some irrelevant props
/>
{/* some irrelevant info and other components . . . */}
)});
.
.
.
.
return(
<Stage
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
//style={{ border: '1px solid grey' }}
ref={stageRef}
>
<Layer>
<Rect
x = {0}
y= {0}
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
fill={"white"}
stroke={"white"}
strokeWidth={5}
/>
{theTextObjs}
</Layer>
</Stage>
//some more components
)
inside of TextBox.js (grandchild component)
import React from "react";
import { useSelector} from 'react-redux';
export function TextBox({textEditVisible, textX,fill,textY,textValue,fontSize,width,height,fontStyle,align,id,onDragStart,isSelected,onClick,onChangeEnd,onContextMenu,onChangeEdit,onClickedit,onKeyDownEdit,event}) {
const selectedTextObj = useSelector(state => state.selectedTextObj)
const TextObjs = useSelector(state => state.TextObjs)
const dispatch = useDispatch()
//
//some irrelevant info
// ...
return (
<>
{/* more irrelevant info */}
</>
);
}
When using a different React renderer such as Konva, you need to wrap the components within the different Renderer within a new provider. In the case of Konva, the children of Stage.
See this issue.
const store = useStore()
return ( <Stage
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
//style={{ border: '1px solid grey' }}
ref={stageRef}
>
<Provider store={store}>
<Layer>
<Rect
x = {0}
y= {0}
width={ window.innerWidth * 2}
height={ window.innerHeight * 2}
fill={"white"}
stroke={"white"}
strokeWidth={5}
/>
{theTextObjs}
</Layer>
</Provider>
</Stage>
Related
I apologize for such a newbie question, but how I can realize switching between tabs using react-redux. How to reproduce this logic using the storage My inital code:
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = { tab: 0 };
}
switchingTabs = (event, value) => {
this.setState({
tab: value,
});
};
render() {
return (
<div className="App">
<Container>
<AppBar className="bar" position="static">
<Tabs value={this.state.tab} onChange={this.switchingTabs}>
<Tab label="Commits Info"></Tab>
<Tab label="User info"></Tab>
</Tabs>
</AppBar>
<TabBackbone value={this.state.tab} index={0}></TabBackbone>
<TabBackbone value={this.state.tab} index={1}></TabBackbone>
<Content></Content>
</Container>
</div>
);
}
Index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
I tried to do it myself, but I don't know how to export value to reducer
It sounds like you're just getting started with Redux, which is great!
You need a state that will represent your tab selection:
export interface IState {
tabNumber : number
}
export initialState : IState = {
tabNumber : 0
}
You are going to need to define a reducer:
export function appReducer(state=initialState, action : AnyAction) : IState{
// state reduction logic here
}
Then create a store:
export const store = createStore(appReducer); // import {createStore} from "redux";
Then wrap your application or portion thereof in a Provider that takes your store:
<Provider store={store}> {/* import {Provider} from "react-redux"; */}
<App/>
</Provider>
That said, I would consider whether you need Redux. I typically use the React Context API, especially in situations like this where the context is intended to essentially perform the function of a higher-order function.
I am using leaflet in my react code and I am not using react-leaflet. I want to pass a react component or jsx code to binbPopup function to every tooltip.
let marker = new L.marker(...).bindPopup(<div>Hi</div>)
bindPopup gets string as a input so I cannot use jsx. I also tried to use react portals but still it doesn't work.
What is the solution for this problem?
You can use renderToString method of ReactDOMServer to convert React component to markup string.
import React, { Component } from "react";
import ReactDOM from "react-dom";
import ReactDOMServer from "react-dom/server";
import * as L from "leaflet";
import "./styles.css";
const CustomReactPopup = () => {
return (
<div style={{ fontSize: "24px", color: "black" }}>
<p>A pretty React Popup</p>
</div>
);
};
class App extends Component {
componentDidMount() {
var map = L.map("map").setView([51.505, -0.09], 13);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© OpenStreetMap contributors'
}).addTo(map);
L.marker([51.5, -0.09])
.addTo(map)
.bindPopup(ReactDOMServer.renderToString(<CustomReactPopup />))
.openPopup();
}
render() {
return (
<div>
<div id="map" />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working example here: https://codesandbox.io/s/leaflet-with-react-znk11
I wanna know where <ThemeProvider/> should be placed in React app.
I'd come up with two solutions about it.
1, <ThemeProvider/> should be used 'Just Once' in top-root component
like index.js or App.js file created by 'create-react-app' tool.
2, <ThemeProvicer/> should be placed in 'Each root of React-component'
literally.
for clarification, I'll show you some example.
there is just two component, 'Red' and 'Blue' <div> tag.
1, <ThemeProvider/> used 'Just Once'
// In './red.js'
import React from 'react'
import styled from "styled-components"
const Red = styled.div`background: ${props => props.theme.mainColor}`
export default function RedDiv() {
return (
//NOT using ThemeProvider
<Red />
)
}
// In './blue.js'
......
const Blue = styled.div`background: ${props => props.theme.subColor}`
export default function BlueDiv() {
return (
<Blue />
)
}
// In './App.js'
import React, { Component } from 'react'
import { ThemeProvider } from "styled-components"
import myTheme from "./myTheme
import Red from "./red"
import Blue from "./blue"
export default class App extends Component {
render() {
return (
//only used here just once
<ThemeProvider theme={myTheme}>
<>
<Red />
<Blue />
</>
</ThemeProvider>
)
}
}
2, <ThemeProvider/> used 'Each root of React-component'
// In './red.js'
import React from 'react'
import styled, { ThemeProvider } from "styled-components"
const Red = styled.div`background: ${props => props.theme.mainColor} `
export default function RedDiv() {
return (
<ThemeProvider theme={myTheme}>
<Red />
</ThemeProvider>
)
}
// In './blue.js'
......
const Blue = styled.div`background: ${props => props.theme.mainColor}`
export default function BlueDiv() {
return (
<ThemeProvider theme={myTheme}>
<Blue />
</ThemeProvider>
)
}
// In './App.js'
import React, { Component } from 'react'
import Red from "./red"
import Blue from "./blue"
export default class App extends Component {
render() {
return (
<>
// <ThemeProvider/> is not used
<Red />
<Blue />
</>
)
}
}
there is maybe some typo on the code above, but I hope that this example will convey my idea clearly.
I use it only once, inside index.js.
Also a good place to add some global styles, if you need them. I use them for resetCSS (http://meyerweb.com/eric/tools/css/reset/) and some baseCSS rules like box-sizing etc.
index.js
import { createGlobalStyle, ThemeProvider } from 'styled-components';
import theme from './styles/theme';
import resetCSS from './styles/resetCSS';
import baseCSS from './styles/baseCSS';
import { BrowserRouter as Router} from "react-router-dom";
const GlobalStyle = createGlobalStyle`
${resetCSS}
${baseCSS}
`;
React.DOM.render(
<React.Fragment>
<GlobalStyle/>
<Router>
<ThemeProvider theme={theme}>
<App/>
</ThemeProvider>
</Router>
</React.Fragment>
,document.getElementById('root')
);
I want to import this in my react native project's Appjs view.
I tried many ways but its not working.I mean i want to render it inside My view. How Can i Import and show this file in my Appjs. Can anyone can please help me, Its very important for me.
Here is my code:
import ForwardRef from '../../constants/UI_login/Home_Landing_Page/BackgroundComponent'
import React from "react";
import Svg, { Defs, LinearGradient, Stop, Rect } from "react-native-svg";
/* Adobe XD React Exporter has dropped some elements not supported by react-native-svg: style */
const BackgroundComponent = ({ svgRef }) => (
<Svg width={375} height={247} viewBox="0 0 375 247" ref={svgRef}>
<Defs>
<LinearGradient
id="a"
x1={0.5}
y1={0.807}
x2={0.5}
y2={1}
gradientUnits="objectBoundingBox"
>
<Stop offset={0} stopColor="#fff" />
<Stop offset={1} stopColor="#fff" stopOpacity={0} />
</LinearGradient>
</Defs>
<Rect className="a" width={375} height={247} />
</Svg>
);
const ForwardRef = React.forwardRef((props, ref) => (
<BackgroundComponent svgRef={ref} {...props} />
));
export default ForwardRef;
App.js
import React from 'react';
import { StyleSheet} from 'react-native';
//import {Actions} from 'react-native-router-flux';
import Routes from './components/Routes';
import {firebaseConfig} from "./constants/ApiKeys";
import ForwardRef from '../../constants/UI_login/Home_Landing_Page/BottomNavigationComponent'
import {AppContainer} from './components/Navigation'
import * as firebase from 'firebase';
if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig); }
console.ignoredYellowBox = ['Setting a timer'];
export default class App extends React.Component {
render() {
return (
<AppContainer/>
<ForwardRef/>
);
}
}
Now i am getting a black blank space there
You are using a default export and not a named one, so instead of
import {ForwardRef} from "..."
you have to write
import ForwardRef from "..."
:)
Please try to do the following:
open the AppContainer component file;
in the head of the file add import your BackgroundComponent component;
and add the <ForwardRef/> to the render return method:
I am new to ReactJS, but familiar with React Native. I am trying to to get a basic map component to be displayed.
My map component is
WaterMapView.js
import React, { Component } from 'react';
import { Map, InfoWindow, Marker, GoogleApiWrapper } from 'google-maps-react';
export class WaterMapView extends Component {
render () {
console.log(' I am here ');
return (
<Map
google={this.props.google}
style={styles.mapStyle}
initialCenter={{
lat: 40.854885,
lng: -88.081807
}}
zoom={15}
/>
)
}
}
const styles = {
mapStyle: {
height: '100%',
width: '100%'
}
}
export default GoogleApiWrapper({
apiKey: 'AIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
})(WaterMapView)
This component is embedded in MainDashboard.js as follows :
import React, { Component } from 'react';
import windowSize from 'react-window-size';
import WaterMapView from './WaterMapView';
class MainDashboard extends Component {
render () {
const height = this.props.windowHeight;
const {
containerStyle,
headerStyle,
navigationStyle,
mainPageStyle,
eventPageStyle,
mapPageStyle,
mapDisplayStyle,
mapPropertiesStyle
} = styles;
return (
<div style={{ ...containerStyle, height }} >
<div style={headerStyle} >
</div>
<div style={navigationStyle} >
</div>
<div style={mainPageStyle} >
<div style={eventPageStyle} >
</div>
<div style={mapPageStyle} >
<div style={mapDisplayStyle} >
<WaterMapView />
</div>
<div style={mapPropertiesStyle} >
</div>
</div>
</div>
</div>
);
};
};
My App.js component is :
import React from 'react';
import MainDashboard from './MainDashboard';
const App = () => {
return (
<div>
<MainDashboard />
</div>
)
};
export default App
And index.js is :
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './Components/App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
I am using React version 16.0.0 and google-maps-react version 1.1.0
I get an error accompanied by a dump of code. The error is :
TypeError: Cannot read property 'array' of undefined
I am not including the dump in this post. I can add that if required.
The problem seems very basic as the I do not even see the console.log statement 'I am here' in WaterMapView.js component.
Let me know what am I missing.
<div style={mapDisplayStyle} >
WaterMapView
</div>
Should be
<div style={mapDisplayStyle} >
<WaterMapView />
</div>
Otherwise react just interprets WaterMapView as a string and displays the string. When you want to use/render the component you need to add < > to id.