2017-08-15 88 views
1

考慮到這個僞代碼:的setState /使用狀態的外部功能反應

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的上下文是未知的...

+0

您是否嘗試過在你的'someFunc'刪除'export',並把這個功能您'MyComp內'班? – Jacky

+0

@Jacky當然可以工作。但是我在幾個組件中使用'someFunc()'... – Stophface

+1

也許你可以使用HOC來管理你的狀態,並將道具傳遞給你的包裝組件。 https://facebook.github.io/react/docs/higher-order-components.html#use-hocs-for-cross-cutting-concerns –

回答

2

您不能將組件的狀態設置在組件的外部,因爲它是組件的本地狀態。如果您需要更新共享的狀態,請創建一個存儲(redux存儲)。

就你而言,你可以在一個地方定義一些函數,並將它傳遞給特定的狀態變量或整個狀態。在完成某些功能後,返回修改的狀態並使用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}); 
    } 
+0

我不想使用redux的原因是因爲組件中的本地狀態更新僅適用於樣式。對我來說,只使用REDX僅用於組件的造型聽起來不太合理...... – Stophface

0

這一切都取決於你想要達到的目標。乍一看,我可以看到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; 
     } 
    } 
} 

是添加到您的減速器爲您的商店。

將所有組件包裝在提供程序中。

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

現在,您可以在提供程序的所有子組件上使用redux連接!

像這樣:

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。這是你的最終目標!薩加斯很棒!如果你陷入困境讓我知道!

+0

我不想使用REDX的原因是因爲組件中的本地狀態更新僅用於造型。對我而言,僅使用redux僅用於組件的造型聽起來不太合理...... – Stophface

+0

這很公平。那麼你可以將道具傳遞給孩子或將params傳遞給你的someFunc函數someFunc(params)' – sourRaspberri

0

最好的顯然是使用某種外部庫管理這個。正如其他人所建議的,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>

+0

我不想使用redux的原因是因爲從組件中的本地狀態更新只是爲了造型。對我而言,僅僅爲組件的造型使用redux聽起來不太合理...... – Stophface

+0

@Stophface,好的。這不是一個redux解決方案順便說一句,不知道你是否注意到。 :) – Chris

+0

我注意到了。把你也指給我redux,這就是爲什麼我加:) – Stophface

0

父組件例如當你定義的回調和管理全局狀態:

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

0

沒有可以甚至一個部件的外部使用的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