[EN] Let’s Write – it’s working!
We got it! React finally started to listen me :D It required a lot of work but finally succeeded. Page starts working. It’s not yet the most important part, however, we have something on which we can based.
Path to target
I had some problems with running routing but now we have this. At this moment my router.js file looks like this:
import React from 'react' import { Router, Route, browserHistory, IndexRoute } from 'react-router' import MainLayout from './components/layouts/main-layout' import IndexContainer from './components/home/index-container' import LoginContainer from './components/user/login/login-container' export default ( <Router history={browserHistory}> <Route path='/' component={MainLayout}> <IndexRoute component={IndexContainer} /> <Route path="login" component={LoginContainer} /> </Route> </Router> )
Here is a suppport of the main layout (<Route path=’/’ component={MainLayout}> ). Value in path attribut means that this path should be displayed for all pages in out domain.
Then we have another nested paths. First of them (<IndexRoute component={IndexContainer} /> ) is responsible for display component when user types only our domain without specific path. This is simply the equivalent of index.html file in traditional websites.
The last path supports address our-domain/login . In this case it display login page.
Most problems with React-Router was due to confusion with display of nested elements. Still somewhere missed call this.props.children . Sometimes I did typos which were hard to find :P I should turn on JSLint again :D
Important: At this moment application doesn’t allow go to concrete page by typing address in browser. When we type our-domain/login we get an error 404. It’s caused by the fact that I haven’t yet prepared the server. I use default setting in http-server which doesn’t return main file of page for every address. So now you can navigate between pages only by clicking the links in the application.
How you look like?!
Previously I try write all styles by myself. Finally I failed in this and now I use the framework. First I tried to use Material-UI which looks nice. But using it is too difficult for me. Hard to change anything. A lot of things doesn’t work when I try to use small components. Additionally Material-UI is using strange way of attaching theme.
After that I made a decision about throwing Material-UI. From now I use React-Bootstrap library which gives access to Bootstrap through components.
As I said at first I was going to take care of the home page. Over the weekend I was able to do this:
Of course this is not final result but it shows which direction I want to go. In this place I recommend free photos stock. This photo is very nice and I can using it without limits or charges.
I try to make site so that well looked on different screen sizes. But now I don’t stick to it at 100%. I prefer first to do something what works and refine the details of look at the end of.
Texts I’ll invite later.
If someone is interested homepage component code it looks like this:
import React from 'react' import { Jumbotron, Button, Row, Col } from 'react-bootstrap' const Home = React.createClass({ render: function() { return ( <div> <Jumbotron className="header-container"> <h1 className="header-title">Begin your story.</h1> <p className="header-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio massa, malesuada in libero non, pharetra varius justo.</p> <p><Button className='header-signin' bsSize="large" bsStyle="primary">Sign up now</Button></p> </Jumbotron> <Row> <Col mdOffset={2} md={8}> <Row> <Col md={12}> <h2 className="home-title">Begin your story with Let's Write!</h2> </Col> </Row> <Row className="home-section"> <Col xsHidden md={6} > </Col> <Col md={6}> <h3>Lorem ipsum2:</h3> <ul> <li>Test1</li> <li>Test1</li> <li>Test1</li> <li>Test1</li> </ul> </Col> </Row> <Row className="home-section"> <Col md={6}> <h3>Lorem ipsum:</h3> <ul> <li>Test1</li> <li>Test1</li> <li>Test1</li> <li>Test1</li> </ul> </Col> <Col xsHidden md={6} > </Col> </Row> </Col> </Row> </div> ) } }) export default Home
React-Boostrap allows writing clean code. In future I’ll split this view into smaller components.
Action!
In project I use Redux. Even I have code which uses it! At this moment I support changing user’s state to logged-in or logged-out.
After click „Login” from menu we go to simple login page:
For now the form data is not supported. After click „Sign in” user will change state to logged-in and will be added basic data. As yet data is entered manually in code.
For logged-in user changes the home page:
We are changing
A support for login I have in component login-container:
import React from 'react' import Login from './login' import store from '../../../store' import { browserHistory } from 'react-router' import * as actions from '../../../actions/user/user-actions' const LoginContainer = React.createClass({ render: function() { return ( <Login loginUser={this.loginUser} /> ) }, loginUser: function() { store.dispatch(actions.loginUserSuccess({ firstName: 'Marek', lastName: 'Zając' })) browserHistory.push('/') } }) export default LoginContainer
Function loginUser is passed to Login component and bind to „Sign in” button. In this function is located sending action to Redux. Responsible for this is method dispatch(). We passed to it action which we want to execute. My actions I create by methods that I have in a different folder. At this moment I have defined two actions for user:
import * as types from '../action-types' export function loginUserSuccess(user){ return { type: types.LOGIN, userData: user } } export function logoutUserSuccess(){ return { type: types.LOGOUT } }
Types of action I get from other file. These are simply strings stored in variables.
Handling action
Reducer is responsible for handling the action. User actions deals with user-reducer:
import * as types from '../actions/action-types' const initialState = { isLogged: false, userData: {} } const userReducer = function(state = initialState, action) { switch(action.type) { case types.LOGIN: return Object.assign({}, state, {isLogged: true, userData: action.userData}) case types.LOGOUT: return Object.assign({}, state, {isLogged: false, userData: {}}) } return state } export default userReducer
As the parameter is passed current application state. If the application is just starting and hasn’t state yet we use default values.
Reducer based on action type changes state of the application. Method assign() allows create new object based on existing one and changed part of data. I do this because reducer shouldn’t modifying passed objects but returning new ones.
User-reducer is responsible for user’s state only. Thanks to the proper configuration we can separate different reducers:
import { combineReducers } from 'redux' import userReducer from './user-reducer' var reducers = combineReducers({ userState: userReducer }) export default reducers
In future I’ll be adding here next reducers for next parts of application.
Waiting
At the end I’ll show how to support changing state. For example for component which display home page it looks like this:
import React from 'react' import store from '../../store' import { connect } from 'react-redux' import Home from './index' import DashboardContainer from '../dashboard/index-container' const IndexContainer = React.createClass({ render: function() { if(this.props.isLoggedIn) { return (<DashboardContainer/>) } else { return (<Home />) } } }) const mapStateToProps = (store) => { return { isLoggedIn: store.userState.isLogged } } export default connect(mapStateToProps)(IndexContainer)
In the code I use React-redux library. Thanks to this I can simply use connect() method. Thanks to this method our component will change when state of selected values will change. It’ll listen to change state. In this case important for us is only information if user is logged in. Method mapStateToProps() is responsible for „translation” values stored by Redux to parameters passed to component. Component works as if it just passed parameters. It doesn’t know that Redux is responsible for this.
Summary
Finally, I did something that works. I feel more confident in the world of React.
I’m sure I made a lot of mistakes so I’m looking forward to all the comments from people who work with this technology longer ;)
Current code you can find on GitHub: https://github.com/zajacmarekcom/letswrite. It’s not perfect but first I want to do something that works. I’ll clean up later.
I’ll soon have to take care of key features of the application :P I encourage you to follow this blog and look at the fanpage on Facebook ;)
Leave a Comment