簡體   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