繁体   English   中英

setState/use State in external function react

[英]setState/use State in external function react

考虑到这个伪代码:

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{...}
}

如何将函数someFunc()绑定到Component的上下文? 我在各种组件中使用它,因此将它们收集在一个文件中是有意义的。 现在,我收到错误“无法读取任何未定义的内容”。 this的来龙去脉不得而知……

您不能在组件外部设置状态,因为它是组件的本地状态。 如果您需要更新共享的状态,请创建一个存储(redux 存储)。

在您的情况下,您可以在一个地方定义 someFunction 并将特定状态变量或整个状态传递给它。 在 someFunction 中完成后,返回修改后的状态并使用 setState 在您的组件中更新它。

export function someFunc(state) {
    if(state.whatever) {...}
    const newState = { ...state, newValue: whateverValue }
    return newState
}

_anotherFunc = () = > {
        ....
        const newState = this.someFunc(this.state);
       this.setState({newValue: newState});
    }

这不是 React 实践,它可能会导致很多问题/错误,但 js 允许这样做:

模块 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 
       });
    }

然后在你的 react-app 模块中使用它:

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>);
  }
}

这是一个愚蠢的例子:) 只是为了向您展示如何做到这一点

setState 有一种函数形式,甚至可以在组件之外使用。

这是可能的,因为 setState 的签名是:

* @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.

见丹的推文: https : //twitter.com/dan_abramov/status/824308413559668744

这一切都取决于您要实现的目标。 乍一看,我可以为您看到 2 个选项。 一个创建子组件,两个:使用 redux,因为 redux 在所有子组件之间提供单一状态。

第一个选项:

export default class parentClass extends Component {
    state = {
        param1: "hello".
    };

    render() {
        return (
            <Child param1={this.state.param1}/>
        );
    }
}
class Child extends Component {
    render() {
        console.log(this.props.param1);
        return (
            <h1>{this.props.param1}</h1>
        );
    }
}

现在,上面的子组件将具有从其父渲染函数传递的道具定义的props.param1

上面的方法可行,但我可以看到您正在尝试建立一组“通用”功能。 选项 2 通过为您的应用程序/项目创建单一状态来提供一种方法。 如果您之前没有使用过 redux,一旦掌握了它,它就会非常简单地使用。 我现在将跳过设置http://redux.js.org/docs/basics/UsageWithReact.html

像这样制作一个减速器:

import * as config from './config';//I like to make a config file so it's easier to dispatch my actions etc
//const config.state = {param1: null}
//const config.SOME_FUNC = "test/SOME_FUNC";

export default function reducer(state = config.state, action = {}) {
    switch(action.type) {
        case config.SOME_FUNC:
            return Object.assign({}, state, {
                param1: action.param1,
            });
        break;
        default:
            return state;
        }
    }
}

将其添加到您商店的减速器中。

将所有组件包装在 Provider 中。

ReactDOM.render(
    <Provider store={store} key="provider">
        <App>
    </Provider>,
    element
);

现在您将能够在提供程序的所有子组件上使用 redux connect!

像这样:

import React, {Component} from 'react';
import {connect} from 'react-redux';

@connect(
    state => (state),
    dispatch => ({
        someFunc: (param1) => dispatch({type: config.SOME_FUNC, param1: param1}),
    })
)
export default class Child extends Component {

    eventFunction = (event) => {
        //if you wanted to update the store with a value from an input
        this.props.someFunc(event.target.value);
    }

    render() {
        return (
            <h1>{this.props.test.param1}</h1>
        );
    }
}

当您习惯了 redux 时,请查看https://github.com/redux-saga/redux-saga 这是你的最终目标! 萨加斯很棒! 如果你卡住了,请告诉我!

最好的办法显然是使用某种外部库来管理这个。 正如其他人所建议的那样,Redux 和 MobX 对此有好处。 使用高阶组件来包装所有其他组件也是一种选择。

但是,这是上述解决方案的替代解决方案:


你可以使用标准的JavaScript类(而不是作出反应成分),并在通过this来,你是从类调用该函数。

这比较简单。 我在下面创建了一个简单的示例,其中状态从另一个类的函数更改; 看看:

 class MyApp extends React.Component { constructor() { super(); this.state = {number: 1}; } double = () => { Global.myFunc(this); } render() { return ( <div> <p>{this.state.number}</p> <button onClick={this.double}>Double up!</button> </div> ); } } class Global { static myFunc = (t) => { t.setState({number: t.state.number*2}); } } ReactDOM.render(<MyApp />, document.getElementById("app"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"><div>

父组件示例,您可以在其中定义回调并管理全局状态:

 export default class Parent extends Component { constructor() { super(); this.state = { applyGlobalCss: false, }; } toggleCss() { this.setState({ applyGlobalCss: !this.state.applyGlobalCss }); } render() { return ( <Child css={this.state.applyGlobalCss} onToggle={this.toggleCss} /> ); } }

然后在子组件中,您可以使用道具和回调,例如:

 export default class Child extends Component { render() { console.log(this.props.css); return ( <div onClick={this.props.onToggle}> </div> ); } } Child.propTypes = { onToggle: PropTypes.func, css: PropTypes.bool, };

好吧,对于您的示例,我可以看到您可以以更简单的方式执行此操作,而不是传递任何内容。

由于您想更新状态的值,您可以从函数本身返回它。

只需使您在组件中使用的函数异步并等待该函数返回一个值并将状态设置为该值。

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>
    );
  }
}


在 SomeOtherFile.js 中

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

  // and the blahh blahh algorithm
}

你应该使用反应上下文

Context 允许我们将一个值传递到组件树的深处,而无需显式地将其贯穿每个组件。 这是来自 react docs 的一个用例:为当前主题创建一个上下文(默认为“light”)。

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} />;
  }
}

资源: https ://reactjs.org/docs/context.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM