React上下文useReducer没有正确更新

时间:2019-06-10 19:28:00

标签: javascript reactjs react-hooks

我无法让reducer与 React 上下文一起使用。在buttonbar.js中,有两个按钮应该用来更新状态。通过过滤当前数据来更新状态。单击按钮,我没有收到任何错误,但是它也没有执行任何操作。我认为问题出在减速器上。

context.js

import React, { useState, useEffect } from "react";
import * as moment from "moment";
import axios from "axios";

export const Context = React.createContext();

const url = "https://projects.fivethirtyeight.com/polls/polls.json";

export const filterReducer = (state, action) => {
  switch (action.type) {
    case "SHOW_ALL":
      return state.polls;
    case "SHOW_APPROVAL":
      return state.polls.filter(e => e.type === "trump-approval");
    default:
      return state.polls;
  }
};

export function Provider({ children }) {
  let intialState = {
    polls: [],
    dispatch: action => this.setState(state => filterReducer(state, action))
  };

  const [state, setState, dispatch] = useState(intialState);

  useEffect(() => {
    var dateRange = moment()
      .subtract(7, "days")
      .calendar();

    axios
      .get(url)
      .then(res => {
        setState({
          polls: res.data
            .filter(e => Date.parse(e.endDate) >= Date.parse(dateRange))
            .reverse()
        });
      }, [])
      .catch(error => console.log(error));
  }, []);

  return (
    <Context.Provider value={[state, setState, dispatch]}>
      {children}
    </Context.Provider>
  );
}

// export const Consumer = Context.Consumer;

buttonbar.js

import React, { useContext, useState, useEffect, useReducer } from "react";
import { Context, filterReducer } from "../context";

const ButtonBar = () => {
  const [state, setState] = useContext(Context);
  const [filter, dispatch] = useReducer(filterReducer, state);

  const showAll = () => {
    dispatch({ type: "SHOW_ALL" });
    console.log("showAll clicked");
  };
  const showApproval = () => {
    dispatch({ type: "SHOW_APPROVAL" });
    console.log("showApproval clicked");
  };

  return (
    <div class="mb-2">
      <button class="btn btn-primary btn-sm" name="all" onClick={showAll}>
        All
      </button>{" "}
      <button
        class="btn btn-primary btn-sm"
        name="trump approval"
        onClick={showApproval}
      >
        Trump Approval
      </button>
    </div>
  );
};

export default ButtonBar;

2 个答案:

答案 0 :(得分:2)

有些事情,您做得不正确。

首先,您正在将initialState与调度方法一起使用,而是尝试使用不正确的第三个参数从from rest_framework.response import Response from rest_framework.decorators import api_view @api_view() def custom_view(request): return Response(status=403) class Foo(...): @staticmethod def process_view(request, view_func, view_args, view_kwargs): try: jwt_token = request.headers["token"] except KeyError: return custom_view(request)获取此调度值

第二,由于您使用的是减速器模式,因此如果使用useState钩子

,最好使用减速器模式

第三,您绝不能在reducer中过滤数据,否则,下一次要显示所有数据时,完整的数据将丢失,仅保留过滤的数据。相反,您必须为此选择器。

相关代码:

useReducer

Working demo

答案 1 :(得分:0)

您错误地使用了useReducer挂钩,仅仅是因为您在组件中使用了useReducer挂钩,并不意味着您正在更新全局上下文状态。

所以在您的buttonbar.js

  const [filter, dispatch] = useReducer(filterReducer, state);

  const showAll = () => {
    dispatch({ type: "SHOW_ALL" });
    console.log("showAll clicked");
  };
  const showApproval = () => {
    dispatch({ type: "SHOW_APPROVAL" });
    console.log("showApproval clicked");
  };

您正在使用化简器正确更新状态,但是它将仅更新本地组件状态,而不更新全局上下文状态。

如果您来自redux,这似乎违反直觉。

在上下文中,状态是在父组件中包含和更改的,因此只需将上面的代码移动到父组件,然后通过上下文访问它即可。

export function Provider({ children }) {
  let intialState = {
    polls: [],
    dispatch: action => this.setState(state => filterReducer(state, action))
  };

  // 2 args not 3
  const [state, setState] = useState(intialState);

  const [filter, dispatch] = useReducer(filterReducer, state);

  const showAll = () => {
    dispatch({ type: "SHOW_ALL" });
    console.log("showAll clicked");
  };
  const showApproval = () => {
    dispatch({ type: "SHOW_APPROVAL" });
    console.log("showApproval clicked");
  };

将状态和函数传递给值prop

   <Context.Provider value={{
                          showAllProp: () => showAll(),
                          showApprovalProp: () => showApproval(),
                          filterProp: filter }}>
      {children}
    </Context.Provider>

然后,您可以使用值props在子组件中访问这些值和函数。

   const context = useContext(Context);  

  <button class="btn btn-primary btn-sm" name="all" onClick={context.showAllProp}>
    All
  </button>{" "}
  <button
    class="btn btn-primary btn-sm"
    name="trump approval"
    onClick={context.showApprovalProp}
  >

从本质上讲,这是将上下文与组件联系起来的方式。