Redux / React - 搜索字段不会立即更新redux状态

时间:2016-03-27 15:57:13

标签: search reactjs state redux

我是redux世界的新手,我正在努力制作报纸应用。我目前正致力于搜索功能,用户可以搜索特定的报纸标题。问题是,当我第一次输入例如'a'时,状态是''。当我输入更多例如'b'时,状态显示该术语是'a',当它应该是'ab'时。我正在使用redux chrome工具来检查这种全局状态。

我的Actioncreator非常简单(仅返回传递给它的术语):

export function search(term) {
  return{
    type:SEARCH,
    term
  }
}

这是减速器:

const SearchReducer = (state = '', action) => {

    switch (action.type) {
        case SEARCH:
            return action.term;
        default:
            return state;
    }

}

这是根减速器:

/*Application state*/
const rootReducer = combineReducers({
    weather: WeatherReducer,
    filters: FilterReducer,
    articles:ArticleReducer,
    search: SearchReducer // this should be 'ab', but is 'a' 
});

这是非常简单的设置。以下是我与redux沟通的方式。

我有我的材料-ui文本字段(我也试过香草输入字段)

<TextField  style={style.searchWidget.search}
            floatingLabelText="Search"
            value={this.state.term}
            onChange={this._onSearchChange}
 />

当用户输入内容时,会触发_onSearchChange func。

_onSearchChange(event) {
    this.setState({term: event.target.value});
    this.props.search(this.state.term);
}

这将设置此搜索组件的当前状态。然后它将调度将更新全局状态的搜索操作。但是无法正常工作。全球状态总是落后一步。

有什么想法吗?

编辑: 看起来它不是redux而是反应。组件状态不会立即更新。正确的术语被传递给actionreducer,因此它不是redux的错。我在设置状态后尝试打印出this.state.term。看起来状态似乎没有更新。

3 个答案:

答案 0 :(得分:4)

这个答案增加了Aniket Nandan指出的内容 - 你在React组件中使用setState而不是依赖上面的props。

使用Redux的主要目的是获取您的状态并将其放在应用程序旁边的容器中。这样做的好处是可以跨多个组件共享您的状态,然后您可以通过props将事物传递到组件树中的组件。

使用状态容器(总是提醒我一些使用状态机)允许您构建应用程序,而不必在树中向下移动回调以使更改返回到顶部。相反,Redux处理对状态的更改,并通过道具将所有内容交给React。

_onSearchChange(event) {
    this.setState({term: event.target.value});
    this.props.search(this.state.term);
}

在那个注释中,看看上面的代码,从你的帖子中,我想知道为什么你将setState设置为该术语,但是然后总是调用你通过道具收到的函数?然后搜索是否从Redux商店调用调度方法?如果没有,那么你的连接不是很正确。

除此之外,如果您正确使用connect(来自react-redux),那么您应该从Redux商店获得调度方法(这通过上下文发生)。

Redux的工作方式更像是这样:

_onSearchChange(event) {
    this.props.dispatch({ type: 'SEARCH', term: event.target.value });
}

然后会发生什么是Redux应该处理状态更新,并且新状态将通过道具从Redux流向React(这通过Redux引擎盖下的所有连接发生,这非常棒!)。

const SearchReducer = (state = '', action) => {

    switch (action.type) {
        case SEARCH:
            return action.term;
            break;
        default:
            return state;
    }

}

根据您的reducer(在^^上面复制)和combineReducers的使用,如果您键入'ab',您应该得到一个{ search: { term: 'ab' } }的状态,它应该是'a' '打字后只'a',而不是落后。

使用setState实际发生了什么,来自道具的方法是初始状态(我假设'')被传递给this.props.search,这是第一次。同时,在输入“a”后,状态正在将组件更新为'a'。然后,下次当你键入'b'时,状态正在更新为'ab',但是this.props.search只是在setState执行完之前从状态接收了该术语 - 而它仍然是'一个'。

这实际上是Redux如此出色的原因之一 - 它提供了一种方法来确保根据自己容器中的用户操作正确更新状态,这样您就可以保证应用程序中的内容同步。

关于这一点,我将为使用Redux留下一条建议:您应该很少发现自己在使用Redux的应用程序中的React组件中使用setState。何时在组件中使用setState的决定应取决于您要设置的状态段是否仅存在于该组件中,而应用程序的其余部分不需要知道它。我想不出一个例子,任何我能提供的都可能是非常人为的。到那时,我无法想到的原因是因为我认为在应用程序中有这样一个用例是非常罕见的。

因此,您应该坚持只使用Redux存储中的dispatch方法,并允许Redux通过其工作流处理状态更新,并允许状态通过props向下流向组件。坚持这一流程可以防止很多这些奇怪的“状态不同步”的问题可能发生。

答案 1 :(得分:1)

实际上它与redux无关。在使用react时,您必须记住,一旦更新了您的反应状态,就无法获得更新状态。让我们举个例子。

getInitialState: function() {
  return {
     myState: 0
  }
},

updateState: function(stateVersion) {
   console.log(this.state.myState); //this will print 0
   this.setState({ myState: stateVersion });
   console.log(this.state.myState); //this will print 0
}

现在第一次如果我们调用带有状态版本作为参数的updateState函数,它将为控制台打印0,即使我们发送了1或2或任何数字作为参数。 假设我们已经发送了2作为参数。那么我们可以在下一次使用另一个参数调用该函数时获得该状态。 但反应也照顾到了这一点。 您可能会认为,如果我们更新后状态没有更新,那么我该如何使用它。但反应是一个好孩子...... 如果你调用一个函数来更新状态,然后你调用另一个函数来处理上次更新状态,那么你可以使用它。

我想我已经回答了你的问题,为什么不更新redux状态。

另一个想法是当你使用redux状态为你的搜索减速器时,为什么你也处理反应状态。你可以直接将搜索到的参数传递给你的动作。您可以从reducer状态立即获得该更新。 它将有助于简化代码。

答案 2 :(得分:0)

我找到了解决方案。 React - State not updated 看来setState实际上并没有立即设置状态。 所以我使用了回调函数。

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch  (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                previousX_actionDOWN = ev.getRawX();
                isOnClick = true;
                timePressed = System.currentTimeMillis();
                return false;
            case MotionEvent.ACTION_MOVE:
                if (isOnClick && (Math.abs(previousX_actionDOWN - ev.getRawX()) > SCROLL_THRESHOLD)) {
                    return true;
                } else {
                    return false;
                }
            case MotionEvent.ACTION_UP:
                if (!wasDragged) {
                    return false;
                }
                else {
                    return true;
                }
        }
        return false;
    }

现在当我输入&#39; a&#39;它会记录一个&#39;!