Giter VIP home page Giter VIP logo

react-universal-saga's Introduction

React Universal Saga

React Universal Saga Version Downloads GitHub license

Build Status Dependency Status devDependency Status


Getting Started

Universal React App Starter featuring Redux Saga. Heavily modified version of React Redux Universal Hot Example combined with Redux Saga real-world example.

$ git clone https://github.com/xkawi/react-universal-saga

$ cd react-universal-saga && npm install

$ npm run dev (run in development mode)

Live Demo: react-universal-saga.herokuapp.com

UPDATE: Checkout react-universal-saga-modular for a different structure of react-universal-saga that's more modular, scalable, and maintainable. πŸ˜„

Features

New to React?

Core Concepts to learn if you are new to ReactJS and this repo:

  • Dumb Components (Component)
  • Smart Component (Container)
  • Actions - define available action types
  • Reducers - given previous state and an action, create a new state
  • Sagas - manage or orchestrate event/action dispatching flow (called Side Effects)

Crash Course on React, Redux, and Redux Saga

  1. [Hands-on] Get started with ReactJS

  2. [Reading] Thinking in React way

  3. [Reading] Flux Pattern (video)

  4. [Hand-on] Flux

  5. [Reading] Why someone created a tool called Redux

  6. [Reading] More about Redux

  7. [Hands-on] Getting started with Redux

  8. [Hands-on] More comprehensive hands-on with Redux and React

  9. [Reading] Redux best practices

  10. [Reading + Hands-on] Redux Saga

  11. Everything - Awesome Redux

Development Workflow

Here is a suggested development workflow that works for me:

  1. Define the routes, which helps to reason about the needed containers and components.

  2. Implement dump components + props (state and actions).

    • Each component should define .propTypes for prop's validation, which will throw a warning if the container that uses it do not provides all the props that the component need.
  3. Often, a container = a route page; a container is also where you import necessary components, actions and states (pass down to component) to form a single page.

    • if a container wants to "pre-populate" data during server rendering process, assign Container.preload with sagas that fetches necessary data from the API server. (refer to containers/App.js for an example)
  4. Implement necessary Actions as you define needed containers and components (PS: this implementation is independent from previous steps). It often helps maintainability and readability if action methods are categorized into 2:

    • Actions that manipulate store directly through reducers (e.g. actions/index.js > createRequestTypes method), often to update the state and trigger re-render the components.
    • "LOAD" or "TRIGGER" actions for starting a saga routine/daemon, often to make network call.
  5. Implement Reducers. As you implemented the actions, you will have better idea on how to modify the states for different actions.

Using Redux DevTools

Redux Devtools are enabled by default in development.

If you have the Redux DevTools chrome extension installed it will automatically be used on the client-side instead.

If you want to disable the dev tools during development, set __DEVTOOLS__ to false in /webpack/dev.config.js. DevTools are not enabled during production.

Deployment

$ npm run build

$ npm run start

How Everything Works?

What initially gets run is bin/server.js, which does little more than enable ES6 and ES7 awesomeness in the server-side node code. It then initiates server.js. In server.js we perform data fetching using Redux Saga (details). Aside from serving the favicon and static content from /static, the only thing server.js does is initiate delegate rendering to react-router. At the bottom of server.js, we listen to port 3000 and initiate the API server.

Routing and HTML return

The primary section of server.js generates an HTML page with the contents returned by react-router. Then we perform server-side data fetching, wait for the data to be loaded, and render the page with the now-fully-loaded redux state.

The last interesting bit of the main routing section of server.js is that we swap in the hashed script and css from the webpack-assets.json that the Webpack Dev Server – or the Webpack build process on production – has spit out on its last run. You won't have to deal with webpack-assets.json manually because webpack-isomorphic-tools take care of that.

We also spit out the redux state into a global window.__data variable in the webpage to be loaded by the client-side redux code.

Server-side Data Fetching

The redux-saga provides a mechanism for server-side data fetching from the actual backend API servers/services, when it reaches client-side (React) there is no need to do additional network call. You have to define the Sagas that a container need (refers to containers/UserPage.js > UserPage.preload for example) for server-side to fetch. PS: You have the flexibility to implement additional logic (e.g. handle authentication) when fetching data at server-side rendering stage, as it differs from client-side.

Client Side

The client side entry point is reasonably named client.js. All it does is load the routes, initiate react-router, rehydrate the redux state from the window.__data passed in from the server, and render the page over top of the server-rendered DOM. This makes React enable all its event listeners without having to re-render the DOM.

Redux Middleware

Currently, we only use Saga Middleware and Logger Middleware (for development). If you need to use or add custom middlewares, you can do so by modifying store/configureStore.dev.js (for dev env) or store/configureStore.prod.js (for prod env).

Handling Authentication

If you want to implement authentication/authorization feature, follow this issue posted on redux-saga repo - Question: Authentication flow - it is my main source of reference.

Unit Tests

The project uses Jest to run your unit tests and the Test Utilities from Facebook api.

An example is available at components > User.

To run the tests in the project, just simply run npm test.

Styling

Local Styles

This project uses local styles using css-loader. The way it works is that you import your stylesheet at the top of the render() function in your React Component, and then you use the classnames returned from that import. Like so:

render() { const styles = require('./App.scss'); }

Then you set the className of your element to match one of the CSS classes in your SCSS file, and you're good to go!

<div className={styles.mySection}> ... </div>

Global Style Variables

react-universal-saga support global style variables by defining the variable in theme/style.scss. Once defined, you can use in any scss file so long it is imported (refer to RepoPage.scss for example).

Notable Alternatives

Any contribution is welcome.

Cheers,

Kawi

react-universal-saga's People

Contributors

emil-alexandrescu avatar mehdizonjy avatar nijat13 avatar skydan avatar xkawi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

react-universal-saga's Issues

In this configuration sagas cannot take router events

For example saga will not get '@@router/LOCATION_CHANGE' event on initial loading, because 'store.runSaga(rootSaga);' happens after history is configured.

It must be smth like that:

const store   = configureStore(initialState, browserHistory)
store.runSaga(rootSaga, store.dispatch)

const history = syncHistoryWithStore(browserHistory, store)
const routes  = createRoutes(store)

Replace webpack-isomorphic-tools with isomorphic-webpack

Hello @xkawi πŸ‘‹ ,

I am the author of isomorphic-webpack. isomorphic-webpack is an abstraction used to re-use JavaScript code between server and client. Its been quietly maturing in garage for a few months now andΒ we are using it in production on 2 sites.

However, the Rule of Three states that this project is not mature to be "advertised" as ready for production before at least 3 different projects implement it.

I'd like to work with you to re-implement react-universal-saga using isomorphic-webpack. Hopefully, it will reduce the amount of boilerplate code and make the example itself easier to understand. Along the way I'd like to hear your ideas for improvement and suggestions for documentation.

Have you got time to catch up on Skype/ Slack/ IRC/ ... ?

Postcss adds class suffix to imported css files

Hello,

I've imported a css file from a node module (react-activity) and Postcss or style-loader, or some other processor adds ___[chars] to classes and they do not match the classes added by the module.

Any idea on how to prevent that? I've added another loader that should fix the issue(according to an issue on Postcss) but it does not
loaders: [ { test: /(node_modules)(\/.*css$)/, loader: 'style!css?sourceMap!postcss' },

As of importing it, i'm importing in App.scss file like this @import '../../../node_modules/react-activity/dist/react-activity.css';

Thank you,
Mihai

Large bundle size

First of, Thanks for sharing this repo with the community.

I noticed that the client bundle size is rather large, about 780kb after minification. any idea on how to bring it down a bit?

I managed to cut it down to around 500 by removing "react-bootstrap" (which i won't probably be using) ,and changing Lodash imports from
import _ from 'lodash';
to
import zip from 'lodash/zip'

The bundle still seems a bit large, do you have any recommendation on how to trim it down to a more reasonable size?

Immutable

How to apply Immutable for reducers?

Currently having this error message

"The previous state received by the reducer has unexpected type of "Object". Expected argument to be an object"

Question: Remove Bootstrap

Hey xkawi,

thanks for taking the time to update the react-redux-universal-hot-example. It looks very good so far but I wanna get rid of bootstrap completely and only use sass. Could you help me with that and point me to all the locations in the code?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.