Home Web Front-end HTML Tutorial Detailed introduction to front-end responsive programming solutions and their shortcomings (with code)

Detailed introduction to front-end responsive programming solutions and their shortcomings (with code)

Aug 14, 2018 pm 03:14 PM

What this article brings to you is a detailed introduction to front-end responsive programming and its shortcomings (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you. help.

Many parts of the real world operate in a responsive manner. For example, we will respond to questions from others and give corresponding answers. During the development process, I also applied a lot of responsive design and accumulated some experience, hoping to inspire others.

The main difference between reactive programming (Reactive Programming) and ordinary programming ideas is that reactive programming operates in a push way, while non-reactive programming ideas operate in a pull way. For example, events are a very common reactive programming. We usually do this:

button.on('click', () => {  
    // ...})
Copy after login

In non-reactive mode, it will become like this:

while (true) {  
    if (button.clicked) {        // ...
    }
}
Copy after login

Obviously, no matter whether In terms of code elegance and execution efficiency, non-responsive methods are not as good as responsive designs.

Event Emitter

Event Emitter is an event implementation that most people are familiar with. It is very simple and practical. We can use Event Emitter to implement simple responsiveness. Design, such as the following asynchronous search:

class Input extends Component {  
    state = {        value: ''
    }
    onChange = e => {        this.props.events.emit('onChange', e.target.value)
    }
    afterChange = value => {        this.setState({
            value
        })
    }
    componentDidMount() {        this.props.events.on('onChange', this.afterChange)
    }
    componentWillUnmount() {        this.props.events.off('onChange', this.afterChange)
    }
    render() {        
    const { value } = this.state        
    return (            <input value={value} onChange={this.onChange} />
        )
    }
}
class Search extends Component {  
    doSearch = (value) => {
        ajax(/* ... */).then(list => this.setState({
            list
        }))
    }
    componentDidMount() {
        this.props.events.on(&#39;onChange&#39;, this.doSearch)
    }
    componentWillUnmount() {
        this.props.events.off(&#39;onChange&#39;, this.doSearch)
    }
    render() {
        const { list } = this.state
        return (            <ul>
                {list.map(item => <li key={item.id}>{item.value}</li>)}            </ul>
        )
    }
}
Copy after login

Here we will find that the implementation of Event Emitter has many shortcomings, and we need to manually release resources in componentWillUnmount. Its expressive ability is insufficient, for example, when we need to aggregate multiple data sources when searching:

class Search extends Component {  
    foo = &#39;&#39;
    bar = &#39;&#39;
    doSearch = () => {
        ajax({
            foo,
            bar
        }).then(list => this.setState({
            list
        }))
    }
    fooChange = value => {        this.foo = value        this.doSearch()
    }
    barChange = value => {        this.bar = value        this.doSearch()
    }
    componentDidMount() {        this.props.events.on(&#39;fooChange&#39;, this.fooChange)        this.props.events.on(&#39;barChange&#39;, this.barChange)
    }
    componentWillUnmount() {        this.props.events.off(&#39;fooChange&#39;, this.fooChange)        this.props.events.off(&#39;barChange&#39;, this.barChange)
    }
    render() {        // ...
    }
}
Copy after login

Obviously the development efficiency is very low.

Redux

Redux uses an event stream to implement responsiveness. In Redux, since the reducer must be a pure function, the only way to implement responsiveness is through subscription. in or in middleware.

If you subscribe to the store, since Redux cannot accurately get which data has changed, it can only use dirty checking. For example:

function createWatcher(mapState, callback) {  
    let previousValue = null
    return (store) => {
        store.subscribe(() => {            const value = mapState(store.getState())            if (value !== previousValue) {
                callback(value)
            }
            previousValue = value
        })
    }
}const watcher = createWatcher(state => {  
    // ...}, () => {    // ...})
Copy after login

watcher(store)

This method has two disadvantages. One is that there will be efficiency problems when the data is complex and the amount of data is relatively large; Yes, it would be difficult if the mapState function relied on context. In react-redux, the second parameter of mapStateToProps in the connect function is props. Props can be passed in through the upper component to obtain the required context, but in this way the listener becomes a React component and will be mounted as the component is mounted. And unloading is created and destroyed. If we want this responsiveness to be independent of components, there will be a problem.

Another way is to monitor data changes in middleware. Thanks to the design of Redux, we can get the corresponding data changes by listening to specific events (Action).

const search = () => (dispatch, getState) => {  
    // ...}const middleware = ({ dispatch }) => next => action => {  
    switch action.type {        case &#39;FOO_CHANGE&#39;:        case &#39;BAR_CHANGE&#39;: {            const nextState = next(action)            // 在本次dispatch完成以后再去进行新的dispatch
            setTimeout(() => dispatch(search()), 0)            return nextState
        }        default:            return next(action)
    }
}
Copy after login

This method can solve most problems, but in Redux, middleware and reducer actually implicitly subscribe to all events (Action), which is obviously unreasonable, although there is no performance It's perfectly acceptable under the premise of the question.

Object-oriented responsiveness

ECMASCRIPT 5.1 introduces getters and setters, and we can implement a responsive style through getters and setters.

class Model {  
    _foo = &#39;&#39;
    get foo() {        return this._foo
    }
    set foo(value) {        this._foo = value        this.search()
    }
    search() {        // ...
    }
}// 当然如果没有getter和setter的话也可以通过这种方式实现class Model {  
    foo = &#39;&#39;
    getFoo() {        return this.foo
    }
    setFoo(value) {        this.foo = value        this.search()
    }
    search() {        // ...
    }
}
Copy after login

Mobx and Vue use this method to implement responsiveness. Of course, we can also use Proxy if compatibility is not considered.

When we need to respond to several values ​​and then get a new value, we can do this in Mobx:

class Model {  
    @observable hour = &#39;00&#39;
    @observable minute = &#39;00&#39;
    @computed get time() {        return `${this.hour}:${this.minute}`
    }
}
Copy after login

Mobx will collect the values ​​that time depends on at runtime, and use these Recalculating the value of time when the value changes (triggering the setter) is obviously much more convenient and efficient than the EventEmitter method, and is more intuitive than the Redux middleware.

But there is also a disadvantage here. The computed attribute based on getter can only describe the situation of y = f(x). However, in many cases in reality, f is an asynchronous function, so it will become y = await f( x), getter cannot describe this situation.

For this situation, we can use the autorun provided by Mobx to achieve:

class Model {  
    @observable keyword = &#39;&#39;
    @observable searchResult = []    constructor() {
        autorun(() => {            // ajax ...
        })
    }
}
Copy after login

Since the runtime dependency collection process is completely implicit, a problem often encountered here is the collection Unexpected dependency:

class Model {  
    @observable loading = false
    @observable keyword = &#39;&#39;
    @observable searchResult = []    constructor() {
        autorun(() => {            if (this.loading) {                return
            }            // ajax ...
        })
    }
}
Copy after login

Obviously the loading here should not be collected by the searched autorun. In order to deal with this problem, there will be some extra code, and the extra code will easily bring the opportunity for mistakes. Alternatively, we can also manually specify the required fields, but this method requires some additional operations:

class Model {  
    @observable loading = false
    @observable keyword = &#39;&#39;
    @observable searchResult = []
    disposers = []
    fetch = () => {        // ...
    }
    dispose() {        this.disposers.forEach(disposer => disposer())
    }    constructor() {        this.disposers.push(
            observe(this, &#39;loading&#39;, this.fetch),
            observe(this, &#39;keyword&#39;, this.fetch)
        )
    }
}class FooComponent extends Component {  
    this.mode = new Model()
    componentWillUnmount() {        this.state.model.dispose()
    }    // ...}
Copy after login

And when we need to describe the timeline, Mobx is somewhat unable to do what it does. For example, you need to delay the search for 5 seconds.

Related recommendations:

Puzzle responsive front-end framework version of responsive backend officially released_html/css_WEB-ITnose

Use a very simple responsive front-end development framework_html/css_WEB-ITnose


The above is the detailed content of Detailed introduction to front-end responsive programming solutions and their shortcomings (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Is HTML easy to learn for beginners? Is HTML easy to learn for beginners? Apr 07, 2025 am 12:11 AM

HTML is suitable for beginners because it is simple and easy to learn and can quickly see results. 1) The learning curve of HTML is smooth and easy to get started. 2) Just master the basic tags to start creating web pages. 3) High flexibility and can be used in combination with CSS and JavaScript. 4) Rich learning resources and modern tools support the learning process.

The Roles of HTML, CSS, and JavaScript: Core Responsibilities The Roles of HTML, CSS, and JavaScript: Core Responsibilities Apr 08, 2025 pm 07:05 PM

HTML defines the web structure, CSS is responsible for style and layout, and JavaScript gives dynamic interaction. The three perform their duties in web development and jointly build a colorful website.

What is an example of a starting tag in HTML? What is an example of a starting tag in HTML? Apr 06, 2025 am 12:04 AM

AnexampleofastartingtaginHTMLis,whichbeginsaparagraph.StartingtagsareessentialinHTMLastheyinitiateelements,definetheirtypes,andarecrucialforstructuringwebpagesandconstructingtheDOM.

Understanding HTML, CSS, and JavaScript: A Beginner's Guide Understanding HTML, CSS, and JavaScript: A Beginner's Guide Apr 12, 2025 am 12:02 AM

WebdevelopmentreliesonHTML,CSS,andJavaScript:1)HTMLstructurescontent,2)CSSstylesit,and3)JavaScriptaddsinteractivity,formingthebasisofmodernwebexperiences.

Gitee Pages static website deployment failed: How to troubleshoot and resolve single file 404 errors? Gitee Pages static website deployment failed: How to troubleshoot and resolve single file 404 errors? Apr 04, 2025 pm 11:54 PM

GiteePages static website deployment failed: 404 error troubleshooting and resolution when using Gitee...

How to use CSS3 and JavaScript to achieve the effect of scattering and enlarging the surrounding pictures after clicking? How to use CSS3 and JavaScript to achieve the effect of scattering and enlarging the surrounding pictures after clicking? Apr 05, 2025 am 06:15 AM

To achieve the effect of scattering and enlarging the surrounding images after clicking on the image, many web designs need to achieve an interactive effect: click on a certain image to make the surrounding...

How to implement adaptive layout of Y-axis position in web annotation? How to implement adaptive layout of Y-axis position in web annotation? Apr 04, 2025 pm 11:30 PM

The Y-axis position adaptive algorithm for web annotation function This article will explore how to implement annotation functions similar to Word documents, especially how to deal with the interval between annotations...

HTML, CSS, and JavaScript: Essential Tools for Web Developers HTML, CSS, and JavaScript: Essential Tools for Web Developers Apr 09, 2025 am 12:12 AM

HTML, CSS and JavaScript are the three pillars of web development. 1. HTML defines the web page structure and uses tags such as, etc. 2. CSS controls the web page style, using selectors and attributes such as color, font-size, etc. 3. JavaScript realizes dynamic effects and interaction, through event monitoring and DOM operations.

See all articles