react
The installation
$ cnpm install -g create-react-app $ create-react-app my-demo $ cd my-demo/ $ npm start Copy the code
React official documents are easy to understand and will be used in the following lessons. I won’t repeat too much here.
redux
Redux describes state in terms of ordinary objects.
To change the data in state, initiate an action. Action is also a generic object that describes what happens. Forcing action to describe all changes makes it clear what has changed.
To string action and state together, develop a Reducer function that accepts the state and action and returns the new state. For large applications, it is not possible to write just one reducer function. We can have many small functions to manage a part of state and then use a reducer call to manage the entire state.
function todos1(state, action) {}
function todos2(state, action) {}
function reducerAll(state, action) {
return {
todos1: todos1(state.todos1, action),
todos2: todos2(state.todos2, action),
};
}
Copy the code
The three principles
Single data source
The state of the entire application is stored in an object tree that exists in only one store.
State
Is read-only
The only way to change state is to trigger an action. No view or network request can modify state directly, only the intent to modify it.
Use pure functions to perform modifications
Reducers describes how actions change the State tree.
The Reducer is a pure function that receives the old state and the action returns the new state.
At the beginning, only a Reducer can be written. As the application grows, it can be divided into several small reducers to operate different parts of the State tree respectively.
The basic concept
Action
- through
store.dispatch
将action
(including data) tostore
. isstore
The only source of data. - Essentially,
JavaScript
Normal object, must use a string of typetype
Field saidThe action to be performed(No updatesstate
). General willtype
Defined asString constant. Use separate modules or files for large projectsaction
. Use a separate module or file for definitionaction type
constantIt’s not necessaryYou don’t even need to define it. For small applications, use stringsaction type
It’s more convenient. However, explicitly defining them as constants in large applications would do more good than harm.) - As far as possible in
Action
To pass data. Action
Create a function: returnsaction
The function.
Reducer
-
Take the old state and action and return the new state.
-
It is important to keep reducer pure. Never do this in the Reducer (as long as the incoming parameters are the same, the next state returned must be the same. No special cases, no side effects, no API requests, no variable changes, just perform calculations. :
- Modify the passed parameter;
- Perform operations that have side effects, such as
API
Request and route hops; - Call an impure function, such as
Date.now()
或Math.random()
.
-
Note:
-
Do not change the
state
:Object.assign({},state,{data})
Because the value of the first parameter will change,Must beSet the first parameter to an empty object.- with
{... state,... newState}
To update the data.
-
** Return the old state in default: ** Always return the old state when an action is unknown.
-
-
Writing just one Reducer makes the code look verbose and can be split. Each Reducer is only responsible for part of the global state that he is responsible for. State parameters corresponding to each Reducer are different, respectively corresponding to the part of state data that he manages.
-
Combine reducer with combineReducers() tool class.
-
CombineReducers receives an object and can put all top reducer functions into an independent file. Each reducer function is exposed through export. Then use import * as reducers to get an object with their name as the key:
import { combineReducers } from 'redux' import * as reducers from './reducers' const todoApp = combineReducers(reducers) Copy the code
-
Store
Action to describe what’s happening, and Reducers updates state based on action. A Store is an object to associate with Actions and reducers. Have the following responsibilities:
- Sustainably applied
state
- provide
getState()
Methods to obtainstate
- provide
dispatch(action)
Methods the updatestate
- through
subscribe(listener)
Register listeners - through
subscribe(listener)
The returned function unlogs the listener
Redux
There is only one applicationstore
. You should use it when you need to split fractionsreducer
Combine rather than create multiplestore
Creating a store from reducer is easy:
Import {createStore} from 'redux' import todoApp from './reducers' // combineReducers Merge multiple reducers into a let store = createStore(todoApp)Copy the code
The second parameter to createStore is optional and sets the initial state. State can also be initialized using the state passed in by reducer. If state is not initialized, the state is undefined by default.
The data flow
Strict one-way data flow is at the heart of the Design of the Redux architecture.
The life cycle of data in a Redux application follows four steps:
- call
store.dispatch(action)
: can be called from a specific location Redux store
Call incomingreducer
Function.- The root
reducer
Should put more than onereducer
The outputMerged into a singlestate
The tree. Redux store
Save the rootreducer
The returnedcompletestate
The tree.
The code to understand
Understand Redux with code. Create a React application with create-react-app.
scenario
Store stores array data CART, which is managed by Redux to realize adding, deleting and updating operations.
Actions
/ / SRC/actions/cartActions js / / define the action type character constants export const ADD_TO_CART = ADD_TO_CART "; export const DELETE_FROM_CART = "DELETE_FROM_CART"; export const UPDATE_CART = "UPDATE_CART"; Export function addToCart(product, quantity, unitCost) {return {type: ADD_TO_CART, payload: { product, quantity, unitCost }, }; } export function deleteFromCart(product) { return { type: DELETE_FROM_CART, payload: { product, }, }; } export function updateCart(product, quantity, unitCost) { return { type: UPDATE_CART, payload: { product, quantity, unitCost, }, }; }Copy the code
Reducer
// src/reducers/cartReducers.js import { ADD_TO_CART, UPDATE_CART, DELETE_FROM_CART, } from ".. /actions/cartActions"; // state initialdata const initialState = {cart: [{product: "bread 700g", quantity: 2, unitCost: 90,}, {product: "milk 500ml", quantity: 1, unitCost: 47, }, ], }; The first parameter passed by the reducer can be used to initialize state, Export default function (state = initialState, action) {switch (action.type) {case ADD_TO_CART: { return { ... state, cart: [...state.cart, action.payload], }; } case UPDATE_CART: { return { ... state, cart: state.cart.map((item) => item.product === action.payload.product ? action.payload : item ), }; } case DELETE_FROM_CART: { return { ... state, cart: state.cart.filter( (item) => item.product ! == action.payload.product ), }; } default: return state; }}Copy the code
Assume there are other reducer:
// src/reducers/productsReducer.js
export default function(state = [], action) {
return state;
};
Copy the code
Need to use combineReducers() to integrate:
// src/reducers/index.js
import {combineReducers} from 'redux'
import productsReducer from './productsReducer';
import cartReducer from './cartReducers'
const allReducers = {
products: productsReducer,
shoppingCart: cartReducer,
};
const rootReducer = combineReducers(allReducers);
export default rootReducer
Copy the code
store
// src/store.js
import {createStore} from 'redux'
import rootReducer from './reducers/index'
let store = createStore(rootReducer);
export default store
Copy the code
dispatch
import store from "./store"; import { addToCart,updateCart,deleteFromCart } from "./actions/cartActions"; console.log("initialState", store.getState()); // let unsubscribe = store.subscribe(() => console.log(store.getstate ()))); store.dispatch(addToCart("coffee 500gm", 1, 250)); store.dispatch(addToCart("flour 100g", 1, 250)); store.dispatch(addToCart("juice 2L", 1, 250)); store.dispatch(updateCart("flour 100g", 100, 250)); Store. Dispatch (deleteFromCart("coffee 500gm", 1, 250)) // Unsubscribe ();Copy the code
When the code is complete, executenpm start
Run, you can see the printed log.
React
–Redux
-
Install the react – story:
npm install –save react-redux
-
Write the React code and use the Provider class to wrap the React application in a Redux container:
import React from 'react'; import ReactDom from 'react-dom'; import {Provider} from 'react-redux'; const App = <h1>Redux Shopping Cart</h1> ReactDom.render( <Provider store={store}> {App} </Provider>, document.getElementById('root') ) Copy the code
This completes the simple integration. Next, learn about React -redux in detail.
The installation
React-redux is not a redux built-in and needs to be installed separately:
npm install –save react-redux
API
<provider store>
Components.
The connect() method can only be used if the root component is nested in
-
Normal React:
ReactDOM.render( <Provider store={store}> <MyRootComponent /> </Provider>, rootEl ) Copy the code
-
React Router
ReactDOM.render( <Provider store={store}> <Router history={history}> <Route path="/" component={App}> <Route path="foo" component={Foo}/> <Route path="bar" component={Bar}/> </Route> </Router> </Provider>, document.getElementById('root') ) Copy the code
Parameters:
Store: redux-store that is globally unique to the application
Children: Root component of the component hierarchy
mapStateToProps(state, [ownProps])
store
To the componentprops
Mapping to: ListeningRedux store
The change,Redux store
Change,mapStateToProps
The function will be called,- Returns a pure object that will correspond to the component
props
A merger. - If the second argument in the callback function is specified
ownProps
, the value of this parameter is passed to the componentprops
And only componentsreceiveTo the newprops
.mapStateToProps
Will also be called
mapDispatchToProps()
- distribution
action
That is, the component tostore
The mapping.
connect()
React-redux provides the connect method for generating container components from UI components. Connect means to connect the two components together
Example: counters
Implement a counter whose value is mapped by Store and increment state by Dispatch by clicking the Increase button.
UI components
- Only responsible for the presentation of the UI, with no business logic
- No state (that is, not used
this.state
This variable) - All data is defined by parameters (
this.props
) to provide - Without using any
Redux
theAPI
const { Component } = require("react");
export default class Counter extends Component{
render(){
const {value,onIncreaseClick} = this.props
return(
<div>
<span>{value}</span>
<button onClick = {onIncreaseClick}>Increase</button>
</div>
)
}
}
Copy the code
The value displayed in this component is computed by state, and onIncreaseClick issues an Action.
Container components
- Responsible for managing data and business logic, not UI rendering
- With internal state
- use
Redux
theAPI
connect
Method to generate a container component
import { connect } from 'react-redux'; import {increaseAction} from '.. /actions' import Counter from '.. /components/count'; function mapStateToProps(state) { return { value: state.count, }; } function mapDispatchToProps(dispatch){return {onIncreaseClick ()=>dispatch(increaseAction)}} Const App =connect(mapStateToProps, mapDispatchToProps)(Counter) export default AppCopy the code
Action
export const increaseAction = {
type:'increase'
}
Copy the code
Reducer
export default function counter(state = { count: 0 }, action) { const count = state.count; switch (action.type) { case "increase": return { count: count + 1 }; default: return state; }}Copy the code
Store
import {createStore} from 'redux'
import counter from './reat-rdx/reducers/index'
const store = createStore(counter);
export default store
Copy the code
Component is used and Provider is included
import App from './reat-rdx/containerComponents/index'
ReactDom.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById("root")
);
Copy the code
Conclusion:
In my understanding, React-Redux contains a container component outside the UI component to handle the state and distribute the action.
React Router
React Router 4. X is a different system from the previous one
The basic routing
Three basic pages: home page, About, user. The following
// Home.js import { Component } from "react"; export default class Home extends Component { render() { return <h2>Home</h2>; } } // User.js import { Component } from "react"; export default class User extends Component { render() { return <h2>User</h2>; } } // About.js import { Component } from "react"; export default class About extends Component { render() { return <h2>About</h2>; }}Copy the code
Control rendering:
// App.js import Home from "./Home"; import Users from "./Users"; import About from "./About"; import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom"; export default function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link To ="/about"> about </Link> /about </li> <li> <Link to="/users"> users </Link> </li> </ul> </nav> {/* switch renders components that match the current URL by Route */} < switch > <Route Path ="/about"> <About /> </Route> <Route path="/users"> < users /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); } // index.js import React from "react"; import ReactDom from "react-dom"; import App from './reat-rout/modules/App' ReactDom.render( <App/>, document.getElementById('root') )Copy the code
Conclusion:
-
<Link to="/about"> about </Link> // <Route path="/about"> // Load the about component when the Route is /aboutCopy the code
Nested routing
Add Topics component:
import { Route, Link, Switch, useParams, useRouteMatch, } from "react-router-dom"; export default function Topics() { let match = useRouteMatch(); Return (<div> <h2>Topics</h2> <ul> <li> <Link to={' ${match-. url}/components'}> components </Link> </li> <li> < Link to = {` ${(match. Url)} / props - v - state `} > props v. Tate < / Link > < / li > < / ul > {/ * switchable viewer has its own switch * /} < switch > < the Route path={`${match.path}/:topicId`}> <Topic /> </Route> <Route path={match.path}> <h3>please select a topic</h3> </Route> </Switch> </div> ); } function Topic() { let { topicId } = useParams(); return <h3>requested topic ID :{topicId}</h3>; }Copy the code
Display:
import Home from "./Home"; import Users from "./Users"; import About from "./About"; import Topics from "./Topics"; import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom"; export default function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/users">Users</Link> </li> <li> <Link to="/topics">Topics</Link> </li> </ul> </nav> {/* switch renders components matching the current URL by Route */} < switch > <Route path="/about"> < about /> </Route> <Route path="/users"> <Users /> </Route> <Route path="/topics"> <Topics /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); }Copy the code
Conclusion:
We have seen the following faces in this section. Don’t worry, read on for more details
-
let match = useRouteMatch(); Copy the code
-
<Link to={`${match.url}/components`}>Components:{match.url}</Link> Copy the code
-
<Route path={`${match.path}/:topicId`}> Copy the code
-
let { topicId } = useParams(); Copy the code
Main ingredients
React Router components fall into three categories:
- The router, like
<BrowserRouter>
and<HashRouter>
- Route matching machine, e.g.
<Route>
and<Switch>
- navigation, e.g.
<Link>
.<NavLink>
and<Redirect>
The router
-
uses the regular URL path. These are usually the best-looking urls, but they require the server to be configured correctly.
-
stores the current location in the hash part of the URL, so the URL looks like http://example.com/#/your/page. Since hashes are never sent to the server, this means that no special server configuration is required.
-
To use the router, just be sure to render it at the root of the element hierarchy.
Route matching machine
-
There are two routing matching components: Switch and Route. When
is rendered, it searches its children
content to find a URL match for its current path. When an object is found, it renders it
and ignores all other objects.
-
Therefore, the higher specificity of
should be placed in the higher position.
-
If there is no
match,
renders nothing.
<Route path="/about"> < about /> </Route> // Notice how the two routes are sorted. More specific path= "/contact/ : Id "comes before path=" /contact ", so when looking at individual contacts, The Route /contact/: ID <Route path="/contact/: ID "> < contact/ > </Route> <Route path="/contact"> <AllContacts /> </Route> // This path serves as a back-up if the previous path didn't render anything. Important: routes with a path of "/" will always match urls, because all urls begin with a /. That's why we put this last <Route path="/"> <Home /> </Route> </Switch>Copy the code
The important thing to note is that a
matches the beginning of the URL, not the entire beginning. Therefore,
will always match the url. Therefore, we usually place this at the end of
.
Navigation (Route changer)
-
Navigation is the Link component, similar to the tag.
<Link to="/">Home</Link> // <a href="/">Home</a> Copy the code
-
is a special type of that can set itself to “active” when its to prop matches the current position.
<NavLink to="/react" activeClassName="hurray"> React </NavLink> // When the URL is /react, this renders: // <a href="/react" className="hurray">React</a> // When it's something else: // <a href="/react">React</a> Copy the code
-
Render
any time you want to force navigation. When
renders, it uses its to Prop to navigate.
<Redirect to="/login" /> Copy the code
API
hook
The React Router comes with hooks that let you access the state of the Router and perform navigation from within the components.
useHistory
useLocation
useParams
useRouteMatch
useHistory
Access History for navigation.
import { useHistory } from "react-router-dom";
export default function HomeBtn() {
let history = useHistory();
function handleClick() {
history.push("/");
}
return <button onClick={handleClick}>go Home</button>;
}
Copy the code
useLocation
Returns an object representing the current URL, and a new location object when the URL changes.
import { useLocation } from "react-router-dom";
export default function UseLocation() {
let location = useLocation();
return (
<h3>
location:{location.pathname}
{console.log(location)}
</h3>
);
}
Copy the code
useParams
Object that returns the key/value pair of the URL argument. Parameters that can be used to match routes.
<Route path="topics/:topicId">
<Topic />
</Route>
function Topic() {
let { topicId } = useParams();
return <h3>requested topic ID :{topicId}</h3>;
}
Copy the code
This is above part used, routing nested 】 【 when routing is: http://localhost:3000/topics/props-v-state, topicId props – v – state
useRouteMatch
The useRouteMatch hook attempts to match the current URL in the same way as
. It is useful for accessing match data without actually rendering
.
There are many apis besides hook functions, you can check out the official website for more information.
github
Reference:
Redux Tutorial (Get started quickly)
Redux Chinese document
React-redux Document in Chinese
Redux tutorial (3) : React-redux
The React the Router tutorial
React Router 4.x官网