Always interested in your feedback ❤️
All concepts below are aggregated in Suicrux.
Almost every library has a “clone” (alternative). That means that you can find more than one library to solve a specific task. That means when you see a reference to React Router be sure that there is a “clone” of this library, but for Preact.
Almost every library has a “clone” (alternative). You can find more than one library to solve a specific task. That means when you see a reference to React Router be sure that there is a “clone” of this library, but for Preact.
But this
speed
doesn’t matter in “real-life”. 90% of speed issues caused by bad optimization of your app, not a framework. So there is no difference what library to choose(except size).
Must-have libraries:
react-router
(or another routing library),react-helmet
(easily manipulate tag).
Mobx/Saga/Redux/Flux/Kea — it doesn’t really matter.
When you use any of these libraries — you use the same flux-architecture concept.
redux-thunk
,react-redux
, etc. — obviously.react-router-redux
— sync your library with location. (Also, RRRv5 sometimes doesn’t work as you expect).promise-middleware
— smart solution to use promises as an action payload and evaluate them using middleware. (will cover in next article)
“Styled components” — is a design approach. “Thinking in components, styling in components”.
Styled-components
— is a library to design styled components in React using HOCs
styled-components
— bloated, requires good understanding of CSS methodologies. But it’s very powerful and has a rich API.glamorous
— API similar tostyled-components
, lightweight, good performance.emotion
— API similar tostyled-components
, has “extract mode” that makes it fast.glamor
— lightweight and simple inline-css library.glamorous
is based onglamor
.
What’s a problem with “styled components”?
- Sometimes hard to overwrite your CSS framework.
- There is no styling methodology, and SMACSS/BEM/etc. will not work well.
- Sometimes you could incorrectly connect your app logic with styles.
You have to design your own styling strategy to write configurable, fast, composable components. Personally, I didn’t find any new methodology for styled components, but can give you some recommendations:
- Don’t pass too many different props.
- Don’t make a styled component for every custom component in your app.
- HOCs could save you a lot of time.
- Don’t mix logic props and UI props (font size, color)
Remember that all these libraries were created to solve same issues.
Probably, this article with a comparison of different UI frameworks could help you select a framework for the next project.
If you want fast UI framework then select a framework powered by library like styled-components
or inline-css lib.
Don't know current MUI development progress, but as of July-Aug 2017:
Don’t know current MUI development progress, but as of July-Aug 2017:
- it was(!) slow, but according to the latest news right now perf is better.
- design isn’t 100% material.
Semantic-UI-React — many components out-of-box, but requires full Semantic CSS file. (548 kb ungzipped).
“Ant design” looks great.
As of 2017, your project must be universal. It’s very important. Both server and client must have hot-reloading.
Step-by-step guide how to achieve universality. Also, it’s an alternative to most solutions. One port and FS instead of 2 ports and different FSs.
- Compile both server and client with Webpack
- Extract shared config for both server and client (e.g. loaders, plugins for both server and client)
- Extract your production and development configs in a separate module and save it for the next project.
Frameworks(Next.js) and starters (razzle) supports custom Webpack configs (the end of old-fashioned starters era is soon). Keep in mind, some project supports custom Webpack config only partly. That’s the only reason why starters are still used.
Some plugins you could have missed:
circular-dependency-plugin
— detects circular dependenciesautodll-webpack-plugin
— recompile only updated code, without vendor bundlewrite-file-webpack-plugin
— write files from memory FS to real FS. (e.g. write files from webpack-dev-middleware to FS)assets-webpack-plugin
— get webpack stats (similar towebpack-stats-plugin
, but better)
Flow.
TypeScript is great and has more features than Flow. But keep in mind that when you use TypeScript - you dive into the TypeScript world. That means you use "another" language with own ecosystem.
When you use Flow you just create an abstraction around your dynamic-typed code and still write JavaScript.
Standard code style is ❤️.
If you care about a11y (accesibility), then use eslint-plugin-jsx-a11y
.
It’d be better to use
eslint-plugin-standard
than standard package, some default Standard rules are annoying, likeno-tabs
,no-unused-vars
andindent
.
Add babel-preset-react-optimize
in production.
Don’t forget to add styled-components
plugin, if you use styled-components
library.
Also, module-resolver
plugin is very useful.
There are many approaches to structuring react/redux project. Keep in mind, that this structure may vary according to your framework, setup, etc. For example, Next.js, CRA already have some predefined folders.
├── ...
├── jest_config # Jest configuration lives here
├── src
| ├── client # Entry file for browser
│ ├── common # Sources for both browser and server
│ └── server # Server code
├── webpack_config
│ ├── client # Webpack config for client
│ └── server # Webpack config for server
├── ...
Probably, jest_config and webpack_config dirs are obvious. So let’s take a look at the /src folder.
Here we store code that renders the app in a browser.
This is your browser entry — code that renders an app in a browser, imports framework styles, polyfills, your global styles, PWA setup. It could be in /common
folder too, but putting it into distinct folder seems more semantically correct.
// Styles
import 'semantic-ui-css/semantic.css'
// Fetch and promise polyfill
import 'promise-polyfill'
import 'isomorphic-fetch'
// Application
import React from 'react'
import ReactDOM, {render} from 'react-dom'
import {configureApp, configureRootComponent} from 'common/app'
//
const initialState = window.__INITIAL_STATE__ || {}
const propsForRoot = configureApp(initialState)
const RootComponent = configureRootComponent(propsForRoot)
render(RootComponent, document.getElementById('app'))
if (module.hot) {
module.hot.accept()
}
Your server-side code.
That’s the place where the most interesting things happen.
/common
├── actions # Actions
├── api # API (requests, data management utils)
├── app # App core(boot loader)
├── components # Reusable components
├── constants # Constant values, like months names, etc.
├── containers # App routes
├── pwa # Progressive Web App code (optional)
├── reducers
├── selectors
├── styles # Styled components + global CSS
├── types # Flow types for your app’s entities
Almost every route has own /components
folder where specific for this route components are stored, i.e.:
- container =
containers/App/index.jsx
- route’s component =
containers/App/components/SomeAppItem.jsx
Don't mix API requests with Redux with React containers! Always try to distinct parts of your app into autonomous libraries. Principal of minimal knowledge. Review on all approaches to work with async actions in Redux.
if (componentHasNoState) {
return itsStatelessComponent()
} else if (componentHasSimplePropsState && propsHasNoNestedObjects) {
return itsPureComponent()
} else {
return itsComponent()
}
Keep in mind, that change of component type doesn’t guarantee performance improve.
Follow Dan's guide:
- Container - "smart" React component connected to Redux state.
- Component - "dumb" React component that uses only own props. Can't be connected to Redux.
There are no practical recommendations about structuring /components
folder, except “Atomic” approaches and other heuristics (those have never worked for me). Semantic UI glossary proposes similar to “Atomic” approach that works better than analogs (but still isn’t perfect).
A component is a general term used to refer to any user interface element packaged for distribution.
There are always components that exist in one instance, like Sidebar, Header, Footer, etc. Store singletons in /parts
.
SUI doesn’t propose “parts”.
A view is a common design trope for presenting specific types of website content like comments, or user activity. These are common views: comments, activity feeds, content cards, that are presented in a similar fashion across most websites.
If a component is a parent for other components, represent some content, and it’s dumb then it’s probably a View. Summary:
- huge component
- takes a big place in UI
- dumb or not so smart to be called "Module"
- has many components inside
Component may be an addon, if this component is a wrapper for another component, or a component that could be perfectly replaced by a library, but was developed from scratch (custom spinners, progress bars).
Component is an “addon”, if...:
- it’s a wrapper for another component
- it is small lib implemented inside the project
UI elements are the smallest atomic unit for describing page content. They can exist alone or in groups with shared qualities.
Component is an “element”, if…:
- small + dumb
- widely used in other components
- built from scratch
Collections are heterogeneous group of several ui elements which are usually found together. They may describe ui elements which do not necessarily have to be present.
Collection is a group of different similar components inside itself.
Collection differs from views:
- "view" - represents specific for sites content.
- "collection" - doesn’t represent specific content. Grouped different components.
Modules are UI components that have behaviors as an essential part of their definition. These include things like, accordions, dropdowns, and popups, which require not only a description of how they appear, but also a set of instructions for how to implement their behaviours.
When your component has some logic inside (e.g. onClick
handler), this component is a module. Module is a component logically connected to a parent component.
Behaviors are instructions for UI behaviour that are not attached to a particular physical form. They may describe things like, form validation, state management, or server request routing.
Component that doesn’t exist as UI element, but brings some logic. Like components those implement animations. Example: react-motion
and react-fns
Use Offline-Plugin. It requires zero config as long as you:
- Don't have SSR (sometimes).
- Don't have auth logic that relies on location. (e.g. redirect to
/auth
, if user isn't logged in) - Don't have other logic that interacts with location
- Don’t have specific requirements to caching, cache validation or anything similar that connected to offline.
If you got one of these features — it’d be better to test your PWA setup in different browsers with different behaviors/app flows.
Dissecting Twitter’s Redux Store. You can make your own research and dissect any popular app. Pinterest, for example.
95% of all states in any app can be interpreted as:
interface State {
entities: object;
fetchStatus: 'none' | 'loading' | 'loaded';
errors: object;
}
The main key to Redux development:
Your state is just an in-memory DB.
Don’t store things those could be computed by selectors.
Always use selectors, it’s very important!
What is a "selector"?
If your mapStateToProps
looks like:
const mapStateToProps = (state) => {
// BAD!!!
const {variable} = state.let.var.be.const.hello.world
return {variable}
}
Then you’re doing that wrong, because:
- every time the way you compute some value changes, you have to change it across a whole app.
- every time your state structure changes, you have to fix path to the property across a whole app.
- you connect your computational(selectional) logic with your container, container shouldn’t know about it.
Instead:
import {getThatState} from 'selectors'
// ...
const mapStateToProps = (state) => {
// GOOD!
return {variable: getThatVariable(state)}
}