diff --git a/JavaScript/React/Redux.md b/JavaScript/React/Redux.md new file mode 100644 index 0000000..a30b3da --- /dev/null +++ b/JavaScript/React/Redux.md @@ -0,0 +1,148 @@ +# [Redux](https://redux.js.org/) + +Redux is a pattern and library for managing and updating application state, using events called *actions*. It serves as a centralized store for state that needs to be used across the entire application, with rules ensuring that the state can only be updated in a predictable fashion. + +## Actions, Store, Immutability & Reducers + +### Actions & Action Creators + +An **Action** is a plain JavaScript object that has a `type` field. An action object can have other fields with additional information about what happened. +By convention, that information is stored in a field called `payload`. + +**Action Creators** are functions that creates and return an action object. + +```js +function actionCreator(data) +{ + return { type: ACTION_TYPE, payload: data } // action obj +} +``` + +### Store + +The current Redux application state lives in an object called the **store**. +The store is created by passing in a reducer, and has a method called `getState` that returns the current state value. + +The Redux store has a method called `dispatch`. The only way to update the state is to call `store.dispatch()` and pass in an action object. +The store will run its reducer function and save the new state value inside. + +**Selectors** are functions that know how to extract specific pieces of information from a store state value. + +```js +function configStore(initialState) { + return createStore(rootReducer, initialState); +} + +replaceReducer(newReducer); // replace an existing reducer, useful for Hot Reload + +store.dispatch(action); // trigger a state change based on an action +store.subscribe(listener); +store.getState(); // retireve current state +``` + +### Reducers + +**Reducers** are functions that receives the current state and an action, decide how to update the state if necessary, and return the new state. + +Reducers must **always** follow some specific rules: + +- They should only calculate the new state value based on the `state` and `action` arguments +- They are not allowed to modify the existing `state`. +Instead, they must make *immutable updates*, by copying the existing `state` and making changes to the copied values. +- They must not do any asynchronous logic, calculate random values, or cause other "side effects" + +```js +function reducer(state, action) { + switch(action.type){ + case "ACTION_TYPE": + return { ...state, prop: value }; // return modified copy of state (using spread operator) + break; + + default: + return state; // return unchanged state (NEEDED) + } +} + +// combining reducers +import { combineReducers } from "redux"; + +const rootReducer = combineReducers({ + entity: entityReducer +}); +``` + +## [React-Redux](https://react-redux.js.org/) + +### Container vs Presentational Components + +Container Components: + +- Focus on how thing work +- Aware of Redux +- Subscribe to Redux State +- Dispatch Redux actions + +Presentaional Components: + +- Focus on how things look +- Unaware of Redux +- Read data from props +- Invoke callbacks on props + +### Provider Component & Connect + +Used at the root component and wraps all the application. + +```js +// index.js +import React from 'react' +import ReactDOM from 'react-dom' + +import { Provider } from 'react-redux' +import store from './store' + +import App from './App' + +const rootElement = document.getElementById('root') +ReactDOM.render( + + + , + rootElement +) +``` + +```js +// Component.js +import { connect } from 'react-redux' +import { increment, decrement, reset } from './actionCreators' + +// const Component = ... + +// specifies which state is passed to the component (called on satte change) +const mapStateToProps = (state, ownProps /* optional */) => { + // structure of the props passsed to the component + return { propName: state.property } +} + +// specifies the action passed to a component (the key is the name that the prop will have ) +const mapDispatchToProps = { actionCreator: actionCreator } +// or +function mapDispathToProps(dispatch) { + return { + // wrap action creators + actionCreator: (args) => dispatch(actionCreator(args)) + } +} +// or +function mapDispathToProps(dispatch) { + return { + actionCreator: bindActionCreators(actionCreator, dispatch), + actions: bindActionCreators(allActionCreators, dispatch) + }; +} + +// both args ar optional +// if mapDispatch is missing the dispatch function is added to the props +export default connect(mapStateToProps, mapDispatchToProps)(Component) +```