I am learning react and redux.I am building a mock up project ,While running the project there is no error however nothing is rendered when I click the home route,
my container code,
import Home from '../components/Home.js'
import {
editorContentUpdated
} from '../action/index.js'
const mapStateToProps = (state) => {
return {
editorText: state.editorText
};
}
const mapDispatchToProps = (dispatch) => {
console.log('here')
onBlur: (text) => {
console.log('text', text);
dispatch(editorContentUpdated(text));
}
}
export default (mapStateToProps, mapDispatchToProps)(Home);
reducer code,
const editorReducer = (state, action) =>{
if(state == undefined){
return null
}
console.log('editorReducer',action.payload);
switch(action.type){
case 'EDITOR_SELECTED':
return action.payload
break;
case 'CONTENT_UPDATED':
return action.payload
break;
}
return state;
}
export default editorReducer;
action creater,
export const getPreviewContent = (text) =>{
console.log('previewContent', text);
return{
type:'PREVIEW_SELECTED',
data:text
}
}
export const editorContentUpdated =(text) =>{
console.log('editor content', text);
return {
type:'CONTENT_UPDATED',
data:text
}
}
routes.js file,
import React from 'react'
import{Router,Route,IndexRoute,browserHistory} from 'react-router'
import Layout from '../components/Layout.js'
import Home from '../container/editor.js'
import Preview from '../components/Preview.js'
const routes = (
<Router history={browserHistory}>
<Route path='/' component={Layout}>
<IndexRoute component={Home} />
<Route path='preview' component={Preview} />
</Route>
</Router>
);
export default routes;
layout,
import React from 'react'
import {
Link
} from 'react-router'
import {
connect
} from 'react-redux'
var Layout = React.createClass({
render: function() {
var styles = {
paddingRight: '10px'
}
console.log('custom', this.props.custom);
var custom = this.props.custom;
return ( <html >
<head >
<title > {custom.title} < /title> <link rel = 'stylesheet href = '/style.css' / >
</head> <body >
<nav >
<Link style = {styles
}to = '/' > Home < /Link> <
Link to = '/preview' > Preview < /Link> </nav> {
this.props.children
}<script dangerouslySetInnerHTML = {{
__html: 'window.PROPS=' + JSON.stringify(custom)
}}/> <script src = '/bundle.js' / >
</body> </html>);}
});
var wrapper = connect(
function(state) {
return {
custom: state
};
}
);
export default wrapper(Layout);
Home Component,
import React from 'react'
import {
Link
} from 'react-router'
let Home = React.createClass({
getInitialState: function() {
return {
editorText: ''
}
},
updateText: function(event) {
this.setState({
editorText: event.target.value
})
},
render: function() {
let wrapperStyle = {
width: '100%'
}
let editorStyle = {
float: 'left',
width: '50%',
height: 'auto'
}
let previewBoxStyle = {
float: 'left',
height: 'auto',
width: '50%'
}
return ( <
div style = {
wrapperStyle
} >
<
div style = { editorStyle} >
<textarea rows = '10' cols = '50'onChange = {this.updateText}
value = {this.props.editorText}/> </div> </div>);}
});
There is no error in the console, but the home component is not rendered when I click on the home button,Could anyone suggest me where I am going wrong?
In your Home component I cannot see an you exporting the component and hence The component won't be rendered
export the Home component as
export default Home;
Also when you make use of react-redux you need to make the store available to your Components, for that you need to make use of Provider
import { Provider } from 'react-redux'
import React from 'react'
import{Router,Route,IndexRoute,browserHistory} from 'react-router'
import Layout from '../components/Layout.js'
import Home from '../container/editor.js'
import Preview from '../components/Preview.js'
import { createStore } from 'redux'
import EditorReducer from '/path/to/reducer';
....
const store = createStore(EditorReducer )
const routes = (
<Provider store={store}>
<Router history={browserHistory}>
<Route path='/' component={Layout}>
<IndexRoute component={Home} />
<Route path='preview' component={Preview} />
</Route>
</Router>
</Provider>
);
export default routes;
Related
I'm trying to integrate Firebase to React using React Context. The React project uses the Able template. When I wrap my App component with ContextProvider, it causes an infinite loop.
Here is the code:
./Firebase/firebase.js
import React, { createContext } from "react";
import { useDispatch } from "react-redux";
import firebaseConfig from "./firebaseConfig";
import app from "firebase/app";
import 'firebase/auth';
import 'firebase/firestore';
import "firebase/database";
import { setLoggedUser } from '../store/actions'
// we create a React Context, for this to be accessible
// from a component later
const FirebaseContext = createContext(null);
export { FirebaseContext };
export default ({ children }) => {
let firebase = {
app: null,
database: null,
};
const dispatch = useDispatch();
// check if firebase app has been initialized previously
// if not, initialize with the config we saved earlier
if (!app.apps.length) {
app.initializeApp(firebaseConfig);
firebase = {
app: app,
database: app.database(),
api: {
getUserProfile,
},
};
}
// function to query logged user from the database and
// fire a Redux action to update the items in real-time
function getUserProfile() {
....
}
};
return <FirebaseContext.Provider value={firebase}>{children}</FirebaseContext.Provider>;
};
./index.js
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import App from "./App/index";
import * as serviceWorker from "./serviceWorker";
import reducer from "./store/reducer";
import config from "./config";
import "./assets/scss/style.scss";
import FirebaseProvider from './Firebase/firebase.js';
const store = createStore(reducer);
const app = (
<Provider store={store}>
<BrowserRouter basename={config.basename}>
<FirebaseProvider> <----- cause infinite loading
<App />
</FirebaseProvider>
</BrowserRouter>
</Provider>
);
ReactDOM.render(app, document.getElementById("root"));
The source code that causes the error is where the loadable import component AdminLayout in App/index.js
./App/index.js
import React, { Component, Suspense } from "react";
import { Switch, Route } from "react-router-dom";
import Loadable from "react-loadable";
import "../../node_modules/font-awesome/scss/font-awesome.scss";
import Loader from "./layout/Loader";
import Aux from "../hoc/_Aux";
import ScrollToTop from "./layout/ScrollToTop";
import routes from "../route";
import { FirebaseContext } from '../Firebase/firebase.js';
const AdminLayout = Loadable({
loader: () => {
debugger
return import("./layout/AdminLayout")}, // Cause Infinite Loading
loading: Loader,
});
const App = () => {
const { app, api } = React.useContext(FirebaseContext);
const menu = routes.map((route, index) => {
return route.component ? (
<Route
key={index}
path={route.path}
exact={route.exact}
name={route.name}
render={(props) => <route.component {...props} />}
/>
) : null;
});
return (
<Aux>
<ScrollToTop>
<Suspense fallback={<Loader />}>
<Switch>
{menu}
<Route path="/" component={AdminLayout} />
</Switch>
</Suspense>
</ScrollToTop>
</Aux>
);
}
export default App;
I lost in the debugging process when I try to know what's going on inside this AdminLayout component. This component is coming from the template.
./App/layout/AdminLayout/index.js
import React, { Component, Suspense } from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import Fullscreen from "react-full-screen";
import windowSize from "react-window-size";
import Navigation from "./Navigation";
import NavBar from "./NavBar";
import Breadcrumb from "./Breadcrumb";
import Configuration from "./Configuration";
import Loader from "../Loader";
import routes from "../../../routes";
import Aux from "../../../hoc/_Aux";
import * as actionTypes from "../../../store/actions";
//import '../../../app.scss';
class AdminLayout extends Component {
fullScreenExitHandler = () => {
if (
!document.fullscreenElement &&
!document.webkitIsFullScreen &&
!document.mozFullScreen &&
!document.msFullscreenElement
) {
this.props.onFullScreenExit();
}
};
UNSAFE_componentWillMount() {
if (
this.props.windowWidth > 992 &&
this.props.windowWidth <= 1024 &&
this.props.layout !== "horizontal"
) {
this.props.onUNSAFE_componentWillMount();
}
}
mobileOutClickHandler() {
if (this.props.windowWidth < 992 && this.props.collapseMenu) {
this.props.onUNSAFE_componentWillMount();
}
}
render() {
/* full screen exit call */
document.addEventListener("fullscreenchange", this.fullScreenExitHandler);
document.addEventListener(
"webkitfullscreenchange",
this.fullScreenExitHandler
);
document.addEventListener(
"mozfullscreenchange",
this.fullScreenExitHandler
);
document.addEventListener("MSFullscreenChange", this.fullScreenExitHandler);
const menu = routes.map((route, index) => {
return route.component ? (
<Route
key={index}
path={route.path}
exact={route.exact}
name={route.name}
render={(props) => <route.component {...props} />}
/>
) : null;
});
let mainClass = ["pcoded-wrapper"];
if (
this.props.layout === "horizontal" &&
this.props.subLayout === "horizontal-2"
) {
mainClass = [...mainClass, "container"];
}
return (
<Aux>
<Fullscreen enabled={this.props.isFullScreen}>
<Navigation />
<NavBar />
<div
className="pcoded-main-container"
onClick={() => this.mobileOutClickHandler}
>
<div className={mainClass.join(" ")}>
<div className="pcoded-content">
<div className="pcoded-inner-content">
<Breadcrumb />
<div className="main-body">
<div className="page-wrapper">
<Suspense fallback={<Loader />}>
<Switch>
{menu}
<Redirect from="/" to={this.props.defaultPath} />
</Switch>
</Suspense>
</div>
</div>
</div>
</div>
</div>
</div>
<Configuration />
</Fullscreen>
</Aux>
);
}
}
const mapStateToProps = (state) => {
debugger
return {
defaultPath: state.defaultPath,
isFullScreen: state.isFullScreen,
collapseMenu: state.collapseMenu,
layout: state.layout,
subLayout: state.subLayout,
};
};
const mapDispatchToProps = (dispatch) => {
debugger
return {
onFullScreenExit: () => dispatch({ type: actionTypes.FULL_SCREEN_EXIT }),
onUNSAFE_componentWillMount: () =>
dispatch({ type: actionTypes.COLLAPSE_MENU }),
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(windowSize(AdminLayout));
Could anyone have an idea why this is happening or maybe how to debug to find the problem? Thank you.
EDIT: When I import the AdminLayout directly without using Loadable, it works fine. How to make this work using Loadable?
I want to use rtl layout in my react application. I have used material-ui next version to integrate this application. I have used below code to make application layout rtl. Some components work properly in the rtl layout but some components doesn't affected.
/**
* App.js Layout Start Here
*/
import React, { Component } from 'react';
import { connect } from 'react-redux';
import classnames from 'classnames';
import { MuiThemeProvider } from 'material-ui/styles';
import { IntersectingCirclesSpinner } from 'react-epic-spinners';
import { IntlProvider } from 'react-intl';
import { Redirect, Route } from 'react-router-dom';
import { NotificationContainer } from 'react-notifications';
// app routes
import Dashboard from '../routes/dashboard';
import AppSignUp from '../routes/AppSignUp';
// App locale
import AppLocale from '../lang';
// themes
import lightTheme from './themes/lightTheme';
import darkTheme from './themes/darkTheme';
class App extends Component {
state = {
loading: true
}
componentDidMount() {
let self = this;
setTimeout(() => {
self.setState({ loading: false });
}, 1000);
}
render() {
const { locale, darkMode, rtlLayout } = this.props.settings;
if (this.state.loading) {
return (
<div className="d-flex justify-content-center">
<IntersectingCirclesSpinner color="red" className="rct-loader" />
</div>
);
}
const currentAppLocale = AppLocale[locale.locale];
let theme = '';
if (darkMode) {
theme = darkTheme
} else {
theme = lightTheme
}
if (rtlLayout) {
theme.direction = 'rtl'
} else {
theme.direction = 'ltr'
}
return (
<MuiThemeProvider theme={theme}>
<IntlProvider
locale={currentAppLocale.locale}
messages={currentAppLocale.messages}
>
<React.Fragment>
<NotificationContainer />
<Route path="/dashboard" component={Dashboard} />
<Route path="/signup" component={AppSignUp} />
</React.Fragment>
</IntlProvider>
</MuiThemeProvider>
);
}
}
// map state to props
const mapStateToProps = ({ settings, authUser }) => {
const { user } = authUser;
return { settings, user };
};
export default connect(mapStateToProps)(App);
It doesn't work properly also i have added
<html dir="rtl">...</html>
(1) Don't mutate the theme directly, use getMuiTheme instead:
themeWithDirection = getMuiTheme(theme, { direction: 'rtl' });
Based on: https://github.com/mui-org/material-ui/issues/1926#issuecomment-192736335
(2) Create the RTL component as shown in the Material-UI documentation and put it around your root component:
function RTL(props) {
return (
<JssProvider jss={jss} generateClassName={generateClassName}>
{props.children}
</JssProvider>
);
}
return (
<RTL>
<MuiThemeProvider theme={themeWithDirection}>
{/* your component code */}
</MuiThemeProvider>
</RTL>
);
Props to this answer for explicitly showing what to do with the RTL function.
I'm following this React Router 4 tutorial to add routes to my Meteor / React project:
https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf
When I click links, the URL changes as expected but the route content doesn't appear. If I refresh the page then the route content loads correctly. Here's my code:
Versions: METEOR#1.6.0.1, react-router-dom#4.2.2
main.js
``` JSX
import React from 'react'; // eslint-disable-line no-unused-vars
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
// Start the app with imports
import '../imports/startup/accounts-config.js';
import App from '../imports/ui/layouts/App.jsx';
Meteor.startup(() => {
render((<BrowserRouter><App /></BrowserRouter>), document.getElementById('app'));
});
```
App.js
``` JSX
import React, { Component } from 'react';
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
// game components
import { MapSquares } from '../../api/map/map.js';
// User Accounts
import AccountsUIWrapper from '../AccountsUIWrapper.jsx';
import { Switch, Route, Link } from 'react-router-dom';
import Home from '../pages/home';
import Roster from '../pages/roster';
import Schedule from '../pages/schedule';
function MapSquare(props) {
return (
<span className="mapsquare" key={props.index}>{props.row}, {props.column}</span>
);
}
class App extends Component {
renderMapSquare(mapsquare) {
return (
<MapSquare
index={mapsquare._id}
/>
);
}
render() {
// avoid error while loading data
let data = [];
if (typeof this.props.mapsquares !== 'undefined') {
data = this.props.mapsquares;
}
let rows = [];
let index = 0;
if (data.length !== 0) {
for (let i = 0; i < 5; i++) {
let thisrow = [];
for (let j = 0; j < 2; j++) {
let source = data[index];
let newthing = <MapSquare
key={source._id}
row={source.row}
column={source.column}
/>;
thisrow.push(newthing);
index++;
}
rows.push(<div className="map-row" key={i}>{thisrow}</div>);
}
}
return (
<div className="game">
<AccountsUIWrapper />
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/roster'>Roster</Link></li>
<li><Link to='/schedule'>Schedule</Link></li>
</ul>
</nav>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>
<div className="game-map">
{rows}
</div>
</div>
);
}
}
// provides data to component App
export default withTracker(() => {
Meteor.subscribe('mapsquares');
return {
'mapsquares': MapSquares.find({}, { 'sort': { 'row': 1, 'column': 1 } }).fetch(),
};
})(App);
```
home.js (the roster and schedule pages work the same way)
``` JSX
import React from 'react';
const Home = () => (
<div>
<h1>Home</h1>
</div>
);
export default Home;
```
Any idea what I'm missing here? It so nearly works!
Wrapping my data container in withRouter seems to have done the trick:
App.js:
``` JSX
import { withRouter, Switch, Route, Link } from 'react-router-dom';
...
export default withRouter(withTracker(() => {
Meteor.subscribe('mapsquares');
return {
'mapsquares': MapSquares.find({}, { 'sort': { 'row': 1, 'column': 1 } }).fetch(),
};
})(App));
```
See the docs:
https://reacttraining.com/react-router/web/api/withRouter
I am newbie in react. I read this question , but didn't solve my problem. I think I'm wrong with componentWillReceiveProps comprehension . My component and it's parent are like this:
the parent:
import React from 'react';
import { Router, Route, Link } from 'react-router';
export default class App extends React.Component {
items = [
{id: 1086, title: 'MENU1'},
{id: 1083, title: 'MENU2'},
{id: 1093, title: 'MENU3'}]
renderItems = ()=> {
return this.items.map((item, index)=> {
let url = 'content/' + item.id;
return (<li key={index}><Link to={url} activeClassName="active">{item.title}</Link></li>);
});
}
render() {
return (
<div>
<h1 style={{textAlign:'center'}}>My First React App</h1>
<ul className="nav nav-pills nav-justified">{this.renderItems()}</ul>
{this.props.children}
</div>
);
}
}
the child:
import React, { Component } from 'react';
import UmContent from './UmContent'
import $ from 'jquery';
import ProgressBar from 'progressbar.js';
export default class UmContentContainer extends Component {
state = {
data: ''
}
firstInitial = true;
componentDidMount() {
if (this.firstInitial) {
let props = this.props;
this.sendRequestToServer(props);
this.firstInitial = false;
}
}
sendRequestToServer = (props)=> {
if (!props || !props.params || !props.params.id) {
return;
}
let itemId = props.params.id;
let that = this;
this.setState({data: itemId});
}
componentWillReceiveProps(props, states) {
this.sendRequestToServer(props);
console.log(props.params.id);
}
render() {
return (
<div className="col-md-12">
<h1>{this.state.data}</h1>
</div>);
}
}
and index.js :
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Link,hashHistory } from 'react-router'
import App from './App';
import UmContentContainer from './Umbreco/UmContentContainer';
render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="/content/:id" component={UmContentContainer} />
</Route>
</Router>
), document.getElementById('root'))
after first mounting , console writes "id" twice. I can't understand why?
I found my answer HERE , I was wrong , actually it was about the hashHistory and pushing new url . not componentWillReceiveProps.
Hi I am brand new in react. I am trying to pass data from server to client via React universal rendering. But I am in now luck. Still I can render the html but I am not able to access data through this.props.data
Here is my code
// server.js
app.get('*', (req, res) => {
match({
routes: (<Router>{routes}</Router>),
location: req.url
},
(err, redirect, renderProps) => {
if (err) {
return res.status(500).send(err.message);
} else if (redirect) {
return res.redirect(302, redirect.pathnam + redirect.search);
} else if (renderProps.components.some(component => component === NotFoundPage)) {
res.status(404);
}
let data = [
{
title: 'Godfather'
},
{
title: 'Godfather 2'
}
];
data = JSON.stringify(data);
const renderedApp = renderToString(
<DataWrapper data={data}>
<RouterContext {...renderProps} />
</DataWrapper>
);
res.render('index.ejs', {
renderedApp
});
});
});
// routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import HomePage from './components/routes/HomePage';
import MovieDetailsPage from './components/routes/MovieDetailsPage';
import NotFoundPage from './components/routes/NotFoundPage';
import App from './components/app';
export {
NotFoundPage
};
export default (
<Route path="/">
<IndexRoute component={HomePage} />
<Route path="movie" component={MovieDetailsPage} />
<Route path="*" component={NotFoundPage} />
</Route>
);
// client.js
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import DataWrapper from '../src/DataWrapper';
let data = [];
ReactDOM.render(
<DataWrapper data={data}>
<Router history={browserHistory} routes={routes} onUpdate={window.scrollTo(0, 0)}/>
</DataWrapper>,
document.getElementById('app')
);
// DataWrapper
import React, { Component } from 'react';
class DataWrapper extends Component {
getChildContext () {
return {
data: this.props.data
};
}
render () {
return this.props.children;
}
}
DataWrapper.childContextTypes = {
data: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired
};
export default DataWrapper;
// HomePage.js where I want to access the data in this.props.data
import React, { Component } from 'react';
export default class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
data: this.props.data
};
}
render() {
return (
<div>
<h1>{this.state.data}</h1>
</div>
);
}
}
Can someone please point me in the right direction and explain if possible what I am doing wrong
Thank you
You're currently rendering the children in DataWrapper, but you're not passing in the props.
Not sure if this is the optimal way to do this, but here's how I get the props and state passed in
{this.props.children && React.cloneElement(this.props.children, {
state: this.state
})}
In this use case, I suggest using Redux instead of writing the custom data wrapper. Because
Redux can make the single source of truth, all the components can refer to that, no matter which level it's in (parent or childen) and where is the page rendered (server or client). It can help you to make the architect clearer even it introduces more overhead.
Here's some pseudo code I used before:
// server.js
// configureStore will create a empty store here.
const store = configureStore();
// Then use store.setState or any middleware to prepopulate the store.
....
const jsx = (
<ReduxProvider store={store}>
<StaticRouter context={context} location={req.url}>
<App/>
</StaticRouter>
</ReduxProvider>
);
const html = '<!doctype html><html><head></head>
<body>
<script>
window.REDUX_DATA = ${ JSON.stringify(store.getState()) }
</script>
<div id="root">${ReactDOM.renderToString(jsx)}</div>
</body>
</html>'
res.send(html)
//client.js
const render = App => {
// configStore will create store in client side with initial state passed from server.
const store = configStore(window.REDUX_DATA);
return ReactDOM.hydrate(
<ReduxProvider store={store}>
<BrowserRouter>
<App/>
</BrowserRouter>
</ReduxProvider>,
document.getElementById('root')
);
};
//HomePage.js
class HomePage extends React.Component {
render() {
return (
<div>
this.props.foo.value
</div>
)
}
const mapStateToProps = (state) => ({foo: state.foo});
export default connect(mapStateToProps)(HomePage);
}