setState/use State in external function react

Viewed 30306

Considering this pseudocode:

component.js

...
import {someFunc} from "./common_functions.js"

export default class MyComp extends Component {
    constructor(props) {
        super(props);

    this.someFunc = someFunc.bind(this);

    this.state = {...};
    }

    _anotherFunc = () = > {
        ....
        this.someFunc();
    }

    render() {
        ...
    }
}

common_functions.js

export function someFunc() {
    if(this.state.whatever) {...}
    this.setState{...}
}

How would I bind the function someFunc() to the context of the Component? I use it in various Components, so it makes sense to collect them in one file. Right now, I get the error "Cannot read whatever of undefined". The context of this is unknown...

8 Answers

it's not a React practice and it may cause lot of problems/bugs, but js allows to do it:

Module A:

    export function your_external_func(thisObj, name, val) {
       thisObj.setSate((prevState) => { // prevState - previous state 
         // do something with prevState ...

         const newState = { // new state object
           someData: `This is updated data ${ val }`, 
           [name]: val,
         };
         return newState 
       });
    }

Then use it in your react-app module:

import { your_external_func } from '.../your_file_with_functions';

class YourReactComponent extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state={
      someName: '',
      someData: '',
    };
  }

  handleChange = (e) => {
    const { target } = event;
    const { name } = target;
    const value = target.type === 'checkbox' ? target.checked : target.value;

    your_external_func(this, name, value);
  }

  render() {
    return (<span>
      { this.state.someData }
      <br />
      <input 
        name='someName' 
        value={ this.state.someName }
        onChange={ this.handleChange }
      />
   </span>);
  }
}

It's a stupid example :) just to show you how you can do it

There is a functional form of setState that can even be used outside of a component.

This is possible since the signature of setState is:

* @param {object|function} partialState Next partial state or function to
*        produce next partial state to be merged with current state.
* @param {?function} callback Called after state is updated.

See Dan's tweet: https://twitter.com/dan_abramov/status/824308413559668744

Well for your example I can see you can do this in a simpler way rather than passing anything.

Since you want to update the value of the state you can just return it from the function itself.

Just make the function you are using in your component async and wait for the function to return a value and set the state to that value.

import React from "react"

class MyApp extends React.Component {

  constructor() {
    super();
    this.state = {number: 1};
  }

  theOnlyFunction = async() => {
     const value = await someFunctionFromFile( // Pass Parameters );

     if( value !== false )  // Just for your understanding I am writing this way
     {
        this.setState({ number: value })
     }
  }

  render() {
    return (
      <div>
        <p>{this.state.number}</p>
        <button onClick={this.double}>Double up!</button>
      </div>
    );
  }
}


And in SomeOtherFile.js

function someFunctionFromFile ( // catch params) {
  if( //nah don't wanna do anything )  return false;

  // and the blahh blahh algorithm
}

you should use react Context

Context lets us pass a value deep into the component tree without explicitly threading it through every component. here is a use case from react docs : create a context for the current theme (with "light" as the default).

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // Use a Provider to pass the current theme to the tree below.
    // Any component can read it, no matter how deep it is.
    // In this example, we're passing "dark" as the current value.
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Assign a contextType to read the current theme context.
  // React will find the closest theme Provider above and use its value.
  // In this example, the current theme is "dark".
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

resource: https://reactjs.org/docs/context.html

Related