Tags:
React is declarative.
An advantage vue.js has over react is that react requires JSX and JSX mangles up the data and operations.
A component takes parameters called props
, short for properties, and returns
a hierarchy of views to display via the render
method.
In Haskell speak it's as if a render is a functor and component is fmap
.
component :: render -> props -> hierarchy of views
render
returns a description of what you wish to render
react takes the description and renders it to a screen
render
returns a react element (a lightweight description of what to render)
Each React element is a real JavaScript object that you can store in a variable or pass around your program.
React components can have state by setting this.state
in the constructor,
which should be considered private to the component.
In JavaScript classes, you need to explicitly call super();
when defining the
constructor of a subclass.
We even have a topic on lifting state
When you want to aggregate data from multiple children or to have two child components communicate with each other, move the state upwards so that it lives in the parent component.
The parent can then pass the state back down to the children via props, so that the child components are always in sync with each other and with the parent
It is conventional in React apps to use on* names for the attributes and handle* for the handler methods.
Controlled components child components that receive their state from a parent component.
React components are made up of react elements which so far look just like HTML elements to me.
Imperative rendering
React comes in here: re renders diffs
From: A Case against the GO TO Statement by Edward Dijkstra
we should do (as wise programmers aware of our limitations) our utmost best to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.
Make things snapshottable:
When data changes react re renders entire component
referentially transparent functions/endpoints
Stateful DOM or any stateful UI toolkit
Solution is a virtual DOM which is implemented in a lib called react
immutability plays well with diffing two states
Rather than return a class extending React.Component, write a fn that takes props and returns what should be rendered.
State is similar to props, but it is private and fully controlled by the component. Local state is exactly that: a feature available only to classes.
React may batch multiple setState()
calls into a single update for
performance.
Because this.props
and this.state
may be updated asynchronously, you should
not rely on their values for calculating the next state.
to fix this use a version of setState
that accepts a function e.g
this.setState((prevState, props) => {
counter: prevState.counter + props.increment
});
merges the object you provide into the current state. merging is shallow i.e. leaves other key value pairs untouched
When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
Understanding JavaScript Bind ()
You can use an arrow fn in the callback e.g onClick={(e) => this.handleClick(e)}
The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
Methods run during the life cycle events such as mounting and umounting
componentDidMount
: runs after the component output has been
rendered to the DOM.componentWillUnmount
: this.setState({})
takes an object of new state
constructor
runs before the object is created
modifying state directly e.g this.state.comment = "I'm new..." doesn't lead to a rerender. use set state
The only place where you can assign this.state
is the
constructor
.
Read more under:
App.js has all the paths triggers container for that component
From Kent C. Dotts videos 13-19 Used to maintain component state
Takes the initial value. Returns an array containing the name and a setter for the name.
function MyComponent() {
const [name, setName] = React.useState('');
const handleChange = event => setName(event.target.value);
const [name2, setName2] = React.useState('');
const handleChange2 = event => setName(event.target.value);
return (
<div>
<form>
<!-- htmlFor is like for in html for but JSX-->
<label htmlFor="name""></label>
<input id="name" onChange={handleChange}></input>
</form>
{name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
<form>
<!-- htmlFor is like for in html for but JSX-->
<label htmlFor="name2""></label>
<input id="name2" onChange={handleChange2}></input>
</form>
{name2 ? <strong>Yes? {name}</strong> : <span>Please type in name</span>}
</div>
)
}
A react hook that lets us do things that have side effects e.g save
value to localStorage
.
useEffect takes a lambda and an array of dependencies where we pass what we want to sync the state of the world with the state of our app.
Check the dependency array with eslint-plugin-react-hooks to keep the array up to date.
function MyComponent() {
// First get what's in localStorage
const [name, setName] = React.useState(
/* pass a lambda here to make this initialization lazy
it will only be called to fetch the intiial value and not in
re-renders
*/
() => window.localStorage.getItem('name') || ''
);
const handleChange = event => setName(event.target.value);
// in this case we want to store only name
React.useEffect(() => {
window.localStorage.setItem('name', name);
}, [name]);
const [name2, setName2] = React.useState('');
const handleChange2 = event => setName(event.target.value);
return (
<div>
<form>
<!-- htmlFor is like for in html for but JSX-->
<label htmlFor="name""></label>
<input id="name" onChange={handleChange}></input>
</form>
{name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
<form>
<!-- htmlFor is like for in html for but JSX-->
<label htmlFor="name2""></label>
<input id="name2" onChange={handleChange2}></input>
</form>
{name2 ? <strong>Yes? {name}</strong> : <span>Please type in name</span>}
</div>
)
}
The localStorage pattern is common so there's an npm package for it that has an API like the following:
function useLocalStorage(key, defaultValue='') {
const [state, setState] = React.useState(
() => window.localStorage.getItem(key) || defaultValue
);
React.useEffect(() => {
window.localStorage.setItem(key, state);
}, [state]);
return [state, setState]
}
function MyComponent() {
const [name, setName] = useLocalStorage('name', '');
const handleChange = event => setName(event.target.value);
return (
<div>
<form>
<!-- htmlFor is like for in html for but JSX-->
<label htmlFor="name""></label>
<input id="name" onChange={handleChange}></input>
</form>
{name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
</div>
)
}
It's convention to have custom hooks begin with use
that way
eslint-plugin-react-hooks can check out custom hooks for
mistakes.
A ref is a reference to the DOM node created by react.
To get it we use React.useRef
A ref is an object with a mutable current property
function Tild({children}) {
const tiltRef = React.useRef();
/*
This code runs after react has updated the DOM
Interacting with the DOM is impure so we use a useRef hook
*/
React.useEffect(() => {
console.log(tiltRef.current)
// tiltNode is our DOM node with class name my-class
tiltNode = tiltRef.current
// We may need to clean up our DOM node.
// Ran when the component is unmounted from the page
return () => {
tiltNode.vanillaTilt.destroy()
}
}, []); // the empty dependency array makes us not run useEffect between re-renders.
return (
<div ref={tiltRef} className="my-class">
...
</div>
)
}
Flux architecture for building UIs using react.
Think of flux as new MVC
Difference from MVC
single direction flow:
flux
the dispatcher ensures that until store is done views or anything else can't put an action through the system
advantages:
can trigger actions
enforces no cascading effects once an action goes into store you can't put another until store is done processing it
An implementation of the Flux architecture— a pattern for passing data around in a React app.
Under classic Flux, app state is held within stores. Dispatched actions cause this state to change, afterwhich the views that listen to these state changes will re-render themselves accordingly
/src/component/
Dumb React components that have no knowledge of Redux/src/containers/
Smart React components that are connected to our Redux store/src/services
Abstraction facades for external API (like backend servers)/src/store
All Redux-specific code goes here, including all business-logic of our appThe store directory is organized by domain, each containing:
/src/store/{domain}/reducer.js
Reducer as a default export with all selectors as named exports/src/store/{domain}/actions.js
All the domain action handlers (thunks and plain object creators)The reducer holds the state and updates it.
Rules:
A selector is a pure function that takes the global state as argument and returns some transformation over it Selectors are tightly coupled to reducers and are located inside reducer.js
Redux has no relation to react but works especially well with it because react let's you describe the UI as a function of state. Redux emits state updates in response to actions.
pure functions in redux only 2 things allowed to interact with the store one is a reducer it changes the state others are selectors retrieve data from the state
containers are components aware of global state
all things that fetch lists should be aware of pagination
page numbers
generic for tasks, locations clients
Connects a React component to a Redux store.
connect
is a facade around connectAdvanced
, providing a convenient API for
the most common use cases.
It doesn't modify the component class passed to it; instead it returns a new, connected component class for you to use.
References
The result must be a plain object which will be merged into the component's props.
To allow all components to access the store use a special react redux
component
Read more:
A function that creates an action.
action is a payload of information, and an action creator is a factory that creates an action.
Calling an action creator only produces the action but does not dispatch it. You need to call the store's dispatch fn to actually cause the mutation
Also called a reducing function function that accepts an accumulation and a value and returns a new value
reduce in other langs or fold in haskell.
reduce a collection of values into a single values
most important concept in redux
A helper function that turns an object whose values are different reducing
functions into a single reducing fn you can pass to createStore
.
the resulting reducer calls every child reducer and gethers the resilt into a single state object
The state produced by combineReducers()
namespaces the states of each reducer
under their keys as passed to combineReducers()
.
creates a single redux store that holds the complete state of your app.
Your app should have a single store
args: reducer, preloadedState, enhancer
enhancer: store enhancer optionally specify it to enhance the store with third party capabilities such as middleware, time travel, persistence etc
the only store enhancer that ships with redux is applyMiddleware
.
Lets you wrap the store's dispatch
method
Middleware is composable
Most common use case is to support async actions without much boilerplate code
or lib dependency.
Does so by letting you dispatch async actions
in addition to normal
actions.
https://redux.js.org/api/applymiddleware
lets the action creators invert control by dispatching functions.
They would receive dispatch
as an arg and may call it async.
Such functions are called thunks.
Lets you dispatch a promise async action and dispatches a normal action when the promise resolves.
Middleware is not baked into createStore and is not a fundamental part of the Redux architecture, but we consider it useful enough to be supported right in the core. This way, there is a single standard way to extend dispatch in the ecosystem, and different middleware may compete in expressiveness and utility.
A value that is sent to a dispatching function but not yet ready for consumption by the reducer. It will be transformed by middleware into an action before being sent to the base dispatch fn.
Holds the whole state tree of your app. A store is not a class. It's just an object with a few methods on it.
There's no way to directly modify the store only way is through reducers and only way to trigger reducers is to dispatch actions.
to change data dispatch and action to obtain data we should (need to) go through a selector
we get the state of the application at the time we made the select
Smart components are not allowed to have any logic except dispatching actions. Smart components should always access state through selectors.
Place all business logic inside action handlers (thunks), selectors and reducers.
reference: Medium---Presentational and Container Components aka stateful and pure components among other names
This approach achieves:
Abstract an external API
services must be stateless
In Redux, the reducer is the construct that holds state and updates it
Hackernoon---Redux Step by Step: A Simple and Robust Workflow for Real Life Apps
Other implementions of the store