This article mainly introduces the overall process of react. Let us take a look at this article together
A component of react is obviously composed of dom view and state data, and the two parts are distinct. State is the data center, and its state determines the state of the view. At this time, I found that it seems to be a little different from the MVC development model we have always admired. Without the Controller, how to handle user interaction and who will manage data changes? However, this is not what react should care about, it is only responsible for the rendering of UI. Unlike other frameworks that listen to data and dynamically change the dom, react uses setState to control the update of the view. setState will automatically call the render function to trigger the re-rendering of the view. If there is only a change in state data without calling setState, it will not trigger an update. A component is a view module with independent functions. Many small components form a large component, and the entire page is composed of components. Its benefits are reuse and maintenance.
Where is react’s diff algorithm used? When the component is updated, react will create a new virtual DOM tree and compare it with the previously stored DOM tree. This process uses the diff algorithm, so it is not used when the component is initialized. React makes the assumption that the same components have similar structures, while different components have different structures. Based on this assumption, perform a layer-by-layer comparison. If it is found that the corresponding nodes are different, then directly delete the old node and all the child nodes it contains and replace it with the new node. If it is the same node, only the attributes will be changed.
The diff algorithm for lists is slightly different, because lists usually have the same structure. When deleting, inserting, and sorting list nodes, the overall operation of a single node is much better than comparing each replacement one by one. So when creating the list, you need to set the key value so that react can tell who is who. Of course, it is also possible not to write the key value, but this will usually give a warning, notifying us to add the key value to improve the performance of react.
The two writing methods achieve the same function but the principles are different. You can see the es6 class class As a syntax sugar for the constructor, you can think of it as a constructor. extends implements inheritance between classes - define a class Main to inherit all properties and methods of React.Component, and the life cycle function of the component starts from here. Come. Constructor is a constructor, which is called when instantiating an object. Super calls the constructor of the parent class to create the instance object this of the parent class, and then uses the constructor of the subclass to modify it. This is different from es5's prototypal inheritance. Prototypal inheritance first creates an instantiated object this, and then inherits the parent's prototype method. After understanding this, we will be much clearer when looking at components.
When we use the component , it is actually an instantiation of the Main class - new Main, but react encapsulates this process to make it look more like a label. (If you want to see more, go to the PHP Chinese website React Reference Manual column to learn)
There are three points worth noting: 1. The first letter of the definition class name must be capitalized 2. Because class becomes Without the keyword, the class selector needs to be replaced by className. 3. Classes and modules use strict mode by default, so there is no need to use use strict to specify the running mode.
The component will trigger 5 hook functions during initialization:
1, getDefaultProps()
Set the default props. You can also use dufaultProps to set the default properties of the component.
2. getInitialState()
There is no such hook function when using the es6 class syntax. You can define this directly in the constructor .state. This.props is now accessible.
3. componentWillMount()
is only called when the component is initialized. It will not be called when the component is updated later. It is only called once in the entire life cycle. At this time The state can be modified.
4. render()
#The most important step of react, creating virtual dom, performing diff algorithm, and updating dom tree are all done here . At this point, the state cannot be changed.
5. componentDidMount()
Called after the component is rendered, you can obtain and operate the dom node through this.getDOMNode(), which is only called once .
Five hook functions will also be triggered when updating:
6, componentWillReceivePorps(nextProps)
Not called when the component is initialized, but called when the component accepts new props.
7. shouldComponentUpdate(nextProps, nextState)
is a very important part of react performance optimization. Called when the component accepts new state or props. We can set whether the two props and state before and after comparison are the same. If they are the same, return false to prevent the update, because the same attribute state will definitely generate the same DOM tree, so there is no need Create a new DOM tree and compare the old DOM tree with the diff algorithm, saving a lot of performance, especially when the DOM structure is complex. However, calling this.forceUpdate will skip this step.
8. componentWillUpdata(nextProps, nextState)
is not called when the component is initialized. It is only called when the component is about to be updated. At this time, you can Modify state
9, render()
Not much to say
10, componentDidUpdate( )
is not called when the component is initialized, but is called after the component update is completed. At this time, the dom node can be obtained.
There is also an uninstall hook function
11. componentWillUnmount()
Called when the component is about to be unmounted, some event listeners and timers need to be cleared at this time.
It can be seen from the above that react has a total of 10 periodic functions (render is repeated once). These 10 functions can meet all our needs for component operations. If used well, they can improve development efficiency and component performance. .
Router and Route are components of React. It will not be rendered. It is just a configuration object that creates internal routing rules and displays the corresponding routing address based on the matching routing address. components. Route binds routing addresses and components. Route has a nesting function, indicating the inclusive relationship of routing addresses. This is not directly related to the nesting between components. Route can pass 7 attributes to the bound component: children, history, location, params, route, routeParams, routes. Each attribute contains routing-related information. The more commonly used ones are children (components distinguished by the inclusion relationship of routing), location (including address, parameters, address switching method, key value, hash value). react-router provides the Link tag, which is just an encapsulation of the a tag. It is worth noting that clicking on a link to jump is not the default method. react-router prevents the default behavior of the a tag and uses pushState to change the hash value. The process of switching pages is that when you click the Link label or the Back Forward button, the URL address will change first. Router monitors the address change and matches it to the corresponding component according to the path attribute of Route, changes the state value to the corresponding component and calls setState triggers the render function to re-render the dom.
When there are many pages, the project will become larger and larger. Especially for single-page applications, the initial rendering speed will be very slow. At this time, it needs to be loaded on demand. The only way is to switch to the page. Then load the corresponding js file. The method for react to load on demand with webpack is very simple. Change the component of Route to getComponent, obtain the component using require.ensure, and configure chunkFilename in webpack.
const chooseProducts = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/chooseProducts').default) },'chooseProducts') } const helpCenter = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/helpCenter').default) },'helpCenter') } const saleRecord = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/saleRecord').default) },'saleRecord') } const RouteConfig = ( <router> <route> <indexroute></indexroute>//首页 <route></route> <route></route>//帮助中心 <route></route>//销售记录 <redirect></redirect> </route> </router> );
react advocates a one-way data flow, which transfers data from top to bottom, but from bottom to top or among components that are not on the same data flow Communication between them will become complicated. There are many ways to solve the communication problem. If there is only a parent-child relationship, the parent can pass a callback function as an attribute to the child, and the child can directly call the function to communicate with the parent.
If the component level is nested deeply, you can use Context to pass information. In this way, there is no need to pass functions down layer by layer. Children of any layer can be directly accessed through this.context. .
Components in a sibling relationship cannot communicate directly with each other. They can only use the superior of the same layer as a transfer station. And if the sibling components are the highest-level components, in order to allow them to communicate, they must have another layer of components on their outer layer. This outer component plays the role of saving data and transmitting information. This is actually what redux does. things.
Information between components can also be passed through global events. Different pages can pass data through parameters, and the next page can be obtained using location.query.
Redux is mainly composed of three parts: store, reducer, and action.
store is an object, it has four main methods:
1, dispatch:
用于action的分发——在createStore中可以用middleware中间件对dispatch进行改造,比如当action传入dispatch会立即触发reducer,有些时候我们不希望它立即触发,而是等待异步操作完成之后再触发,这时候用redux-thunk对dispatch进行改造,以前只能传入一个对象,改造完成后可以传入一个函数,在这个函数里我们手动dispatch一个action对象,这个过程是可控的,就实现了异步。
2、subscribe:
监听state的变化——这个函数在store调用dispatch时会注册一个listener监听state变化,当我们需要知道state是否变化时可以调用,它返回一个函数,调用这个返回的函数可以注销监听。
let unsubscribe = store.subscribe(() => {console.log('state发生了变化')})
3、getState:
获取store中的state——当我们用action触发reducer改变了state时,需要再拿到新的state里的数据,毕竟数据才是我们想要的。getState主要在两个地方需要用到,一是在dispatch拿到action后store需要用它来获取state里的数据,并把这个数据传给reducer,这个过程是自动执行的,二是在我们利用subscribe监听到state发生变化后调用它来获取新的state数据,如果做到这一步,说明我们已经成功了。
4、replaceReducer:
替换reducer,改变state修改的逻辑。
store可以通过createStore()方法创建,接受三个参数,经过combineReducers合并的reducer和state的初始状态以及改变dispatch的中间件,后两个参数并不是必须的。store的主要作用是将action和reducer联系起来并改变state。
action是一个对象,其中type属性是必须的,同时可以传入一些数据。action可以用actionCreactor进行创造。dispatch就是把action对象发送出去。
reducer是一个函数,它接受一个state和一个action,根据action的type返回一个新的state。根据业务逻辑可以分为很多个reducer,然后通过combineReducers将它们合并,state树中有很多对象,每个state对象对应一个reducer,state对象的名字可以在合并时定义。
像这个样子:
const reducer = combineReducers({ a: doSomethingWithA, b: processB, c: c })
combineReducers其实也是一个reducer,它接受整个state和一个action,然后将整个state拆分发送给对应的reducer进行处理,所有的reducer会收到相同的action,不过它们会根据action的type进行判断,有这个type就进行处理然后返回新的state,没有就返回默认值,然后这些分散的state又会整合在一起返回一个新的state树。
接下来分析一下整体的流程,首先调用store.dispatch将action作为参数传入,同时用getState获取当前的状态树state并注册subscribe的listener监听state变化,再调用combineReducers并将获取的state和action传入。combineReducers会将传入的state和action传给所有reducer,reducer会根据state的key值获取与自己对应的state,并根据action的type返回新的state,触发state树的更新,我们调用subscribe监听到state发生变化后用getState获取新的state数据。
redux的state和react的state两者完全没有关系,除了名字一样。
上面分析了redux的主要功能,那么react-redux到底做了什么?
如果只使用redux,那么流程是这样的:
component --> dispatch(action) --> reducer --> subscribe --> getState --> component
用了react-redux之后流程是这样的:
component --> actionCreator(data) --> reducer --> component
store的三大功能:dispatch,subscribe,getState都不需要手动来写了。react-redux帮我们做了这些,同时它提供了两个好基友Provider和connect。
Provider是一个组件,它接受store作为props,然后通过context往下传,这样react中任何组件都可以通过contex获取store。也就意味着我们可以在任何一个组件里利用dispatch(action)来触发reducer改变state,并用subscribe监听state的变化,然后用getState获取变化后的值。但是并不推荐这样做,它会让数据流变的混乱,过度的耦合也会影响组件的复用,维护起来也更麻烦。
connect --connect(mapStateToProps, mapDispatchToProps, mergeProps, options)是一个函数,它接受四个参数并且再返回一个函数--wrapWithConnect,wrapWithConnect接受一个组件作为参数wrapWithConnect(component),它内部定义一个新组件Connect(容器组件)并将传入的组件(ui组件)作为Connect的子组件然后return出去。
所以它的完整写法是这样的:connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)
mapStateToProps(state, [ownProps]):
mapStateToProps 接受两个参数,store的state和自定义的props,并返回一个新的对象,这个对象会作为props的一部分传入ui组件。我们可以根据组件所需要的数据自定义返回一个对象。ownProps的变化也会触发mapStateToProps
function mapStateToProps(state) { return { todos: state.todos }; }
mapDispatchToProps(dispatch, [ownProps]):
mapDispatchToProps如果是对象,那么会和store绑定作为props的一部分传入ui组件。如果是个函数,它接受两个参数,bindActionCreators会将action和dispatch绑定并返回一个对象,这个对象会和ownProps一起作为props的一部分传入ui组件。所以不论mapDispatchToProps是对象还是函数,它最终都会返回一个对象,如果是函数,这个对象的key值是可以自定义的
function mapDispatchToProps(dispatch) { return { todoActions: bindActionCreators(todoActionCreators, dispatch), counterActions: bindActionCreators(counterActionCreators, dispatch) }; }
mapDispatchToProps返回的对象其属性其实就是一个个actionCreator,因为已经和dispatch绑定,所以当调用actionCreator时会立即发送action,而不用手动dispatch。ownProps的变化也会触发mapDispatchToProps。
mergeProps(stateProps, dispatchProps, ownProps):
Merge the objects returned by mapStateToProps() and mapDispatchToProps() and the component's own props into new props and pass them into the component. The result of Object.assign({}, ownProps, stateProps, dispatchProps) is returned by default.
options:
pure = true means that the Connect container component will conduct a shallow comparison of the store's state and ownProps in shouldComponentUpdate to determine whether it occurs. changes to optimize performance. If false, no comparison will be performed.
In fact, connect does not do anything. Most of the logic is implemented in the wrapWithConnect function it returns. To be precise, it is implemented in the Connect component defined in wrapWithConnect.
1. The Provider component accepts the redux store as props, and then passes it down through the context.
2. The connect function will bind the mapDispatchToProps object to the store during initialization. If mapDispatchToProps is a function, after the Connect component obtains the store, it will be bound through bindActionCreators according to the incoming store.dispatch and action. Then bind the returned object to the store. The connect function will return a wrapWithConnect function. At the same time, wrapWithConnect will be called and a ui component will be passed in. wrapWithConnect uses class Connect extends internally. Component defines a Connect component. The incoming ui component is a subcomponent of Connect. Then the Connect component will obtain the store through the context and obtain the complete state object through store.getState. Pass the state into mapStateToProps and return the stateProps object, mapDispatchToProps object or The mapDispatchToProps function will return a dispatchProps object. The props of stateProps, dispatchProps and Connect component are merged into props through Object.assign() or mergeProps and passed to the ui component. Then call store.subscribe in ComponentDidMount and register a callback function handleChange to monitor state changes.
3. At this time, the UI component can find actionCreator in props. When we call actionCreator, dispatch will be automatically called. In dispatch, getState will be called to obtain the entire state, and a listener will be registered to monitor state changes. Store Pass the obtained state and action to combineReducers. CombineReducers will pass the state to the sub-reducers according to the key value of the state, and pass the action to all sub-reducers. The reducers will be executed in sequence to judge the action.type, and return if there is one. A new state, or the default if none exists. combineReducers again combines the individual states returned by the child reducers into a new complete state. At this time the state has changed. The subscribe called in the Connect component will listen to the change in state, and then call the handleChange function. Inside the handleChange function, it first calls getState to obtain the new state value and performs a shallow comparison between the old and new states. If they are the same, they will return directly. If they are different, they will call mapStateToProps. Get the stateProps and compare the old and new stateProps briefly. If they are the same, return directly and end without any subsequent operations. If they are not the same, call this.setState() to trigger the update of the Connect component, pass in the ui component, and trigger the update of the ui component. At this time, the ui component gets new props, react --> redux --> The one-time process of react ends.
The above is a bit complicated, the simplified version of the process is:
1. The Provider component accepts the redux store as props, and then passes it down through the context.
2. The connect function receives the store from Provider, then accepts three parameters mapStateToProps, mapDispatchToProps and the component, and passes state and actionCreator into the component as props. At this time, the component can call the actionCreator function to trigger The reducer function returns the new state. Connect listens to the state change and calls setState to update the component and pass the new state into the component.
Connect can be written very concisely. mapStateToProps and mapDispatchToProps are just the callback functions passed in. The connect function will call them when necessary. The names are not fixed, and you may not even need to write a name.
Simplified version: connect(state => state, action)(Component);
The above mentioned knowledge points about react, react-router and redux . But how to integrate them to build a complete project.
1. First quote basic files such as react.js, redux, react-router, etc. It is recommended to install it with npm and quote it directly in the file.
2. Import the required objects and methods from react.js, redux, and react-router.
import React, {Component, PropTypes} from 'react';
import ReactDOM, {render} from 'react-dom';
import {Provider, connect} from 'react-redux' ;
import {createStore, combineReducers, applyMiddleware} from 'redux';
import { Router, Route, Redirect, IndexRoute, browserHistory, hashHistory } from 'react-router';
3. According to It is necessary to create top-level UI components, and each top-level UI component corresponds to a page.
4. Create actionCreators and reducers, and use combineReducers to merge all reducers into one large reducer. Use createStore to create a store and introduce combineReducers and applyMiddleware.
5. Use connect to associate actionCreator, reuder with the top-level ui component and return a new component.
6. Use the new component returned by connect to cooperate with react-router to deploy routing and return a routing component Router.
7. Put Router into the top-level component Provider and introduce store as an attribute of Provider.
8. Call render to render the Provider component and put it in the tag of the page.
You can see that the top-level ui component is actually covered with four layers of components, Provider, Router, Route, and Connect. These four will not make any changes to the view, they are only functional.
Usually when we print props on the top-level ui component, we can see a bunch of properties:
The top-level ui component in the picture above has a total of 18 properties. If you are new to react, you may be confused about where these properties come from. In fact, these properties come from five places:
1 component custom property, 6 objects returned by actionCreator, 4 state returned by reducer, Connect There are 0 component attributes and 7 attributes injected by Router.
You often encounter various problems when using react. If you are not familiar with react, you will be confused. The problem feels baffling and helpless. Next, let’s analyze the problems and points of attention that are easy to encounter in react.
1. setState() is asynchronous
this.setState() will call the render method, but it will not immediately change the value of state. The state is assigned in the render method. Therefore, the value of state obtained immediately after executing this.setState() remains unchanged. The same direct assignment of state will not trigger the update because the render function is not called.
2. Component life cycle
componentWillMount and componentDidMount are only called during initialization.
componentWillReceivePorps, shouldComponentUpdate, componentWillUpdata, componentDidUpdate are only called when the component is updated, not during initialization.
3. The reducer must return a new object to initiate component updates
Because in the connect function, a shallow comparison will be made between the old and new states. If the state only changes in value but the reference address does not change, connect will consider them the same and not trigger an update.
4. Regardless of whether the state returned by the reducer changes, all callback functions registered in subscribe will be triggered.
5. The first letter of the component name must be capitalized. This is the standard for class naming.
6. Before the component is uninstalled, the listening events and timers added to the DOM element need to be cleared manually, because these are not within the control range of react and must be cleared manually.
7. If the component is exposed through export default when loading on demand, default must be added to require.ensure.
require.ensure([], require => { cb(null, require('../Component/saleRecord').default) },'saleRecord')
8、react的路由有hashHistory和browserHistory,hashHistory由hash#控制跳转,一般用于正式线上部署,browserHistory就是普通的地址跳转,一般用于开发阶段。
9、标签里用到的,for 要写成htmlFor,因为for已经成了关键字。
10、componentWillUpdate中可以直接改变state的值,而不能用setState。
11、如果使用es6class类继承react的component组件,constructor中必须调用super,因为子类需要用super继承component的this,否则实例化的时候会报错。
本篇文章到这就结束了(想看更多就到PHP中文网React使用手册栏目中学习),有问题的可以在下方留言提问。
The above is the detailed content of What is the overall process of React? Introduction to the overall process of react (with examples). For more information, please follow other related articles on the PHP Chinese website!