0

I currently have a couple of React components that looks similar in terms of functionality. They all have similar methods used to fetch data a server and update each component's state by making an API to different endpoints.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import AppService from '../lib/service';

class Factorial extends Component {

    constructor(props) {
        super(props);

        this.state = {
            value: '',
        }
    }

    getNext() {
        AppService.getNextFactorial().then(data => {
            this.setState({ value: data.data.gen })
        })
    }

    resetFactorial() {
        AppService.resetNextFactorial().then(data => {
            this.setState({ value: data.data.reset })
        })
    }

    render() {
        return (
            <div className={'functionsWrapper'}>
                <h2> Factorial Sequence Generator </h2>
                <p> Click to get the next value in the sequence </p>
                <button onClick={() => this.getNext()}> Get Next</button>
                <button onClick={() => this.resetFactorial()}> Reset </button>

                <div>
                    <input type="text" id="body" defaultValue={this.state.value} name="body" className="form-input" />
                </div>
            </div>
        )
    }
}

export default withRouter(Factorial);
import React, { Component } from 'react';
import AppService from '../lib/service';

class Fibonacci extends Component {

    constructor(props) {
        super(props);

        this.state = {
            value: '',
        }
    }

    getNext() {
        AppService.getNextFibonacci().then(data => {
            this.setState({ value: data.data.gen })
        })
    }

    resetFibonacci() {
        AppService.resetNextFibonacci().then(data => {
            this.setState({ value: data.data.reset })
        })
    }

    render() {
        return (
            <div className={'functionsWrapper'}>
                <h2> Fibonacci Sequence Generator </h2>
                <p> Click to get the next value in the sequence </p>
                <button onClick={() => this.getNext()}> Get Next</button>
                <button onClick={() => this.resetFibonacci()}> Reset </button>

                <div>
                    <input type="text" id="body" defaultValue={this.state.value} name="body" className="form-input" />
                </div>
            </div>
        )
    }
}

export default Fibonacci;

What I want to achieve is to be able split the functions of each component and make it reusable so that I can have a generic approach

2 Answers 2

2

helper.js

import AppService from '../lib/service';

export function resetFibonacci() {
    AppService.resetNextFibonacci().then(data => {
        this.setState({ value: data.data.reset })
    });    
}

NOTE: use function insted of an arrow function "() => {}"

Fibonacci.js (your component)

import * as Helpers from './helpers.js';
...
resetFibonacci() {
  Helpers.resetFibonacci.call(this);
}

NOTE: bind this to the function scope.

Sign up to request clarification or add additional context in comments.

3 Comments

I really want to avoid declaring state in all the components, I was hoping for an approach where I can reduce duplication of code. btw, thanks for your answer.
Right! so to avoid duplicating code you can create a single component to handle this. I'll right a new answer soon :) Happy to help.
Using bind here just returns a new function, it's not calling it. Using call or apply would make more sense.
1

You can make a function that generates components(which has in it the core functionality), and pass the differences as parameters.

    // componentGenerator.js
    import React, { Component } from 'react';
    import AppService from '../lib/service';

    const componentGenerator = (getNextThing, resetThing, title) => (
    class extends Component {

        constructor(props) {
            super(props);

            this.state = {
                value: '',
            }
        }

        getNext() {
            AppService[getNextThing]().then(data => {
                this.setState({ value: data.data.gen })
            })
        }

        reset() {
            AppService[resetThing]().then(data => {
                this.setState({ value: data.data.reset })
            })
        }

        render() {
            return (
                <div className={'functionsWrapper'}>
                    <h2> {title} </h2>
                    <p> Click to get the next value in the sequence </p>
                    <button onClick={() => this.getNext()}> Get Next</button>
                    <button onClick={() => this.reset()}> Reset </button>

                    <div>
                        <input type="text" id="body" defaultValue={this.state.value} name="body" className="form-input" />
                    </div>
                </div>
            )
        }
    })

    export default componentGenerator;


    // Factorial.js
    import componentGenerator from './componentGenerator';

    export default withRouter(componentGenerator('getNextFactorial', 'resetNextFactorial', 'Factorial Sequence Generator'));


    // Fibonacci.js
    import componentGenerator from './componentGenerator';

    export default withRouter(componentGenerator('getNextFibonacci', 'resetNextFibonacci', 'Fibonacci Sequence Generator'));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.