props
and display the result of their execution. In general, we have 3 types of props
:className
- css class that should be hung on the root element (type 2)value
- the number according to which is used for calculations (1st type)useServerCall
- the parameter that allows you to calculate by means of a request to the server, or locally (type 3) import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; //, Promise import calculateFibonacciExternal from './calculateFibonacci'; export default class Fibonacci extends React.Component { // , static propTypes = { className: PropTypes.string, value: PropTypes.number.isRequired, useServerCall: PropTypes.bool.isRequired, }; // . // state = { loading: true, fibonacci: null, }; // componentWillMount() { // - // , this.calculateFibonacci(this.props.value, this.props.useServerCall, (fibonacci) => { this.setState({ fibonacci: fibonacci, loading: false, }); }); } // props componentWillReceiveProps(nextProps) { // value - if(nextProps.value !== this.props.value) { this.setState({ loading: true, }); this.calculateFibonacci(nextProps.value, nextProps.useServerCall, (fibonacci) => { this.setState({ fibonacci: fibonacci, loading: false, }); }); } } // shouldComponentUpdate(nextProps, nextState) { // , useServerCall return this.props.className !== nextProps.className || this.props.value !== nextProps.value || this.state.loading !== nextState.loading || this.state.fibonacci !== nextState.fibonacci; } // , // , componentWillUnmount() { this.unmounted = true; } unmounted = false; calculationId = 0; // , // calculateFibonacci = (value, useServerCall, cb) => { const currentCalculationId = ++this.calculationId; calculateFibonacciExternal(value, useServerCall).then(fibonacci => { if(currentCalculationId === this.calculationId && !this.unmounted) { cb(fibonacci); } }); }; // render() { return ( <div className={ classnames(this.props.className, this.state.loading && 'loading') }> { this.state.loading ? 'Loading...' : `Fibonacci of ${this.props.value} = ${this.state.fibonacci}` } </div> ); } }
reactRxProps
- converts incoming props
(with some exceptions) into Observables and sends them to your componentreactRxPropsConnect
- takes the logic of working with Observables from your component, allowing you to make it without an internal state (stateless) import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { reactRxProps } from 'react-rx-props'; import { Observable } from 'rxjs'; import calculateFibonacciExternal from './calculateFibonacci'; // Promise Observable . const calculateFibonacci = (...args) => Observable.fromPromise(calculateFibonacciExternal(...args)); class FibonacciReactRxProps extends React.Component { // , Observables //$ ( ) static propTypes = { className: PropTypes.string, value$: PropTypes.instanceOf(Observable).isRequired, useServerCall$: PropTypes.instanceOf(Observable).isRequired, exist$: PropTypes.instanceOf(Observable).isRequired, }; // state = { loading: true, fibonacci: null, }; // componentWillMount() { //useServerCall , this.props.useServerCall$.subscribe(useServerCall => { this.useServerCall = useServerCall; }); //value this.props.value$.switchMap(value => { this.value = value; this.setState({ loading: true, }); return calculateFibonacci(value, this.useServerCall) .takeUntil(this.props.exist$); // }).subscribe(fibonacci => { this.setState({ loading: false, fibonacci: fibonacci, }); }); // className, propTypes - //Observable. . // props, Observables } // render() { return ( <div className={ classnames(this.props.className, this.state.loading && 'loading') }> { this.state.loading ? 'Loading...' : `Fibonacci of ${this.value} = ${this.state.fibonacci}` } </div> ); } } // HoC, ( ) export default reactRxProps({ propTypes: { className: PropTypes.string, value: PropTypes.number.isRequired, useServerCall: PropTypes.bool.isRequired, }, })(FibonacciReactRxProps);
takeUntil(this.props.exist$)
switchMap
import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { reactRxProps, reactRxPropsConnect } from 'react-rx-props'; import { compose } from 'recompose'; import { Observable } from 'rxjs'; import calculateFibonacciExternal from './calculateFibonacci'; const calculateFibonacci = (...args) => Observable.fromPromise(calculateFibonacciExternal(...args)); class FibonacciReactRxProps extends React.Component { // // static propTypes = { className: PropTypes.string, value: PropTypes.number, fibonacci: PropTypes.number, }; //, render() { return ( <div className={ classnames(this.props.className, this.props.loading && 'loading') }> { this.props.loading ? 'Loading...' : `Fibonacci of ${this.props.value} = ${this.props.fibonacci}` } </div> ); } } //compose HoC export default compose( // reactRxProps({ propTypes: { className: PropTypes.string, value: PropTypes.number.isRequired, useServerCall: PropTypes.bool.isRequired, }, }), reactRxPropsConnect({ // props propTypes: { className: PropTypes.string, value$: PropTypes.instanceOf(Observable).isRequired, useServerCall$: PropTypes.instanceOf(Observable).isRequired, exist$: PropTypes.instanceOf(Observable).isRequired, }, // Observables // , : //this -> model //this.props -> props //this.setState -> render connect: (props, render) => { const model = {}; props.useServerCall$.subscribe(useServerCall => { model.useServerCall = useServerCall; }); props.value$.switchMap(value => { model.value = value; render({ loading: true, }); return calculateFibonacci(model.value, model.useServerCall) .takeUntil(props.exist$); }).subscribe(fibonacci => { render({ loading: false, value: model.value, fibonacci: fibonacci, }); }); }, }) )(FibonacciReactRxProps);
Source: https://habr.com/ru/post/346154/
All Articles