Vanilla React without Redux or Flux


(Mikayel) #1

Learning React is not easier then Angular or VueJs, and when you add Redux or Flux abstraction, it may be overkill for beginners…

If you want to communicate with your top component(s) from any child, I am suggestion you to add small “appState” function to your React root component, and pass down the function via Context. No books or videos required.

` const App = React.createClass({

        getInitialState: function(){
            return {};
        },

        appState: function(obj) {
            if (typeof obj == "string") {
                return this.state[obj];
            }
            this.setState(obj);
        },

        childContextTypes: {
            appState: React.PropTypes.func
        },

        getChildContext: function() {
            return {
                appState: this.appState
            };
        },

        render() {
            return <div>{this.props.children}</div>
        }

})`

in any nested component you can use getter or/and setter

contextTypes: {
appState: React.PropTypes.func
},


this.context.appState(“a”) ; //getter
this.context.appState({“a”: 12}); //setter

If you want to see a working example you can find it here https://github.com/mikayel/react-cv


Redux and global state vs. local state
Best practices for HOCs that apply DOM events?
How to access reactjs grand child component Props from Parents ?
(Michel Weststrate) #2

If you want simple communication between components / outside component state, just use MobX :slight_smile:

var appState = mobx.observable({
  todos: [
    {
      title: "Create MobX intro video",
      done: false
    }, 
    {
      title: "Take a nap",
      done: true
    }
  ],
  
  left: function() {
    return this.todos.filter(t => !t.done).length
  }
})

const Todos = mobxReact.observer({appState}) =>
  <div>
    <ul>
    { appState.todos.map((todo, idx) =>
        <Todo todo={todo} key={idx} />
    ) }
    </ul>
    Remaining: {appState.left}
  </div>
)

const Todo = mobxReact.observer(({todo}) => 
  <li>
    <input 
      type="checkbox"
      checked={todo.done} 
      onChange={() => todo.done = !todo.done}
    />
    {todo.title}
  </li>
)

ReactDOM.render(
  <Todos appState={appState} />, 
  document.getElementById('app')
)

(Mikayel) #3

Thanks Michel, I like mobx it is simpler then redux or flux.

In my example I have used pure React and nothing else. I just want to show that without external libs it is possible to create big web apps by using only react, react-router, webpack and npm. I want to show that react is not that complicated. Start from minimum and add all great external libs like mobx or redux when you need it… I was using Dojo and I like it more then jQuery, but jQuery become more popular because it was simpler and easier…


(Michel Weststrate) #4

Ah that is definitely true, just threw mobx in as working with contexts makes react look a bit less trivial than it actual is. Note that even routing is quite doable with a router library, see for example http://jamesknelson.com/simple-routing-redux-react/. Or even simpler libraries will work well, like director. React-router is cool, but most people will use only 10% of it. Similarly browserify is often a bit simpler to setup then webpack for small projects. But well, just ideas :slight_smile: Will you be writing a blog posts for beginners?


(Marc Cyr) #5

Very cool! I think this is a valid demonstration of an approach that can work. I definitely agree that too many times beginners are directed as though they must use Redux and other technologies with React when it is not absolutely required.

At the same time, if you are seeking an architecture that keeps UI components as “dumb” as possible (in that they don’t care about the data… they just render whatever they are told to render), then using context (or using props by passing things down through the tree) can couple your data to your UI too closely.

I have found that separating your data layer (read: business logic) from the UI is beneficial because it allows the same logic to be used with many different UIs. Thinking about using ReactDOM and React Native for iOS and Android: using Redux allows for the data layer to be structured in a way that various UI layers could use the same business logic (and thereby the same API), while the UI for a given platform is uniquely tailored to the usage expectations on that platform.

Going even further, since this is all just JS it is possible to package the business logic (which, in the way I’ve been referring to things would be the Redux bits) into one npm module (using a private npm registry) and shared in multiple places.

This would allow for there to be a Web version, an iOS version, and an Android version – all of which use the same data layer module, but with UIs that account for the different types of users on each application.

Example: a complex web-app that is scaled down to only a few features on mobile - the UIs can differ, but if the data layer is consistent, then developers only change that layer when it is needed and the various UIs just need to consume the new version of the package. The downside to this is a breaking API change will necessitate many changes (potentially), but we’re all used to that with modules anyway when those types of changes happen.

Just some thoughts! Awesome demonstration!


(Mikayel) #6

I agree with you. And yes contexts are less trivial. I think react-router did right thing, by deprecating use of contexts and let developers to decide how to take care of there data flow.
And I think, I may need to create more simpler examples as well.
I like your idea about blog posts, but I can’t write blog posts yet, before I have to learn English :slight_smile:


(Mikayel) #7

Thanks Marc for great comment, before going forward, I want to clarify, I am not huge fan of contexts but I think it is better then global variables, and I always prefer to pass down props if it possible. Just note Redux is using Contexts as well.
And yes dumb UI components (Stateless) are very good practice, but some times you need to use States as well.
And yes, I agree, API has to be sheered between all Web and Mobile apps.

As I understand correctly, you are suggesting to have single business logic for entire app even for all apps (Android and iOS)? If yes, it is software engineering Decorator Pattern (Lets focus on web app only for now).

The alternative pattern that I prefer to use is Composite View Pattern. When each page (it is physical file) is taking care of page related business logic. Page is deciding witch components to load (witch header, left nav, API calls etc…), where and when… You can easily add new page to app or remove or edit without impacting to any other pages. You can reuse the components that have been used in otter pages… and you don’t need to add if conditions.

To make comparison more visual lets look at WordPress and Drupal. WordPress is using Composite View Pattern and Drupal is using Decorator Pattern. In WordPress page is taking care of all businesses logic, in Drupal it is centralized. WordPress is most popular CMS in the world. Why, because it is easy…

I have decided to switch form Angular to React, not because of React Native as most of the cases… I have decided to switch to React because of Virtual Dome and with react I can implement any size of app with Composite View pattern. I haven’t seen anybody using CV pattern with React before, but it was the same in classical web development, it was started without CV pattern :slight_smile:


(Nhan Nguyen) #8

Thanks @mikayel, very useful snippet.
I need your code to build a big form component with many nested component (I use MongoDB with embedded documents)
I’m not sure it’s correct or not? But just avoid Redux for now :frowning:!


(Mikayel) #9

Thank you @virusvn . You can add Redux or anything else easily if you need it in future.
If you have any questions please fell free to ask me.