Javascript 反应上下文useReducer未正确更新
我无法让reducer与React上下文一起工作。在Javascript 反应上下文useReducer未正确更新,javascript,reactjs,react-hooks,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 Co
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;
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;
import React,{useState,useffect}来自“React”;
从“时刻”导入*作为时刻;
从“axios”导入axios;
export const Context=React.createContext();
常量url=”https://projects.fivethirtyeight.com/polls/polls.json";
导出常量filterReducer=(状态、操作)=>{
开关(动作类型){
案例“全部展示”:
返回州。民意测验;
案例“显示批准”:
返回state.polls.filter(e=>e.type==“特朗普批准”);
违约:
返回州。民意测验;
}
};
导出函数提供程序({children}){
让初始状态={
民意测验:[],
dispatch:action=>this.setState(state=>filterReducer(state,action))
};
常量[状态、设置状态、调度]=使用状态(初始状态);
useffect(()=>{
var dateRange=力矩()
.减去(7,“天”)
.日历();
axios
.get(url)
。然后(res=>{
设定状态({
民意测验:res.data
.filter(e=>Date.parse(e.endDate)>=Date.parse(dateRange))
.reverse()
});
}, [])
.catch(错误=>console.log(错误));
}, []);
返回(
{儿童}
);
}
//export const Consumer=Context.Consumer;
buttonbar.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;
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;
import React,{useContext,useState,useffect,useReducer}来自“React”;
从“./Context”导入{Context,filterReducer};
常量按钮栏=()=>{
const[state,setState]=使用上下文(Context);
const[filter,dispatch]=useReducer(filterReducer,state);
常量showAll=()=>{
分派({type:“SHOW_ALL”});
console.log(“showAll clicked”);
};
const showApproval=()=>{
分派({type:“SHOW_APPROVAL”});
console.log(“showApproval”);
};
返回(
全部的
{" "}
特朗普批准
);
};
导出默认按钮栏;
您不正确地使用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");
};
您正在使用reducer正确更新状态,但它只更新本地组件状态,而不会更新全局上下文状态
如果您来自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");
};
将状态和函数传递给值属性
<Context.Provider value={{
showAllProp: () => showAll(),
showApprovalProp: () => showApproval(),
filterProp: filter }}>
{children}
</Context.Provider>
showAll(),
showApprovalProp:()=>showApproval(),
filterProp:filter}>
{儿童}
然后,您可以使用值道具访问子组件中的这些值和函数
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}
>
const context=useContext(context);
全部的
{" "}
这本质上就是如何将上下文与组件连接起来 有几件事你做得不对 首先,您将initialState与分派方法一起使用,而尝试使用不正确的第三个参数从
useState
获取此分派值
Second,因为您使用的是减速器模式,所以最好使用ifuseReducer
hook
第三个,切勿在reducer中过滤数据,否则下次要显示所有数据时,完整数据将丢失,仅保留过滤后的数据。相反,您必须为它设置选择器
相关代码:
import React, {
useEffect,
useContext,
useReducer,
useMemo,
useState
} from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import 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 "ADD_POLLS":
console.log(action.payload);
return action.payload;
default:
return state.polls;
}
};
export function Provider({ children }) {
const [state, dispatch] = useReducer(filterReducer);
useEffect(() => {
var dateRange = moment()
.subtract(7, "days")
.calendar();
axios
.get(url)
.then(res => {
dispatch({
type: "ADD_POLLS",
payload: res.data
.filter(e => Date.parse(e.endDate) >= Date.parse(dateRange))
.reverse()
});
}, [])
.catch(error => console.log(error));
}, []);
return (
<Context.Provider value={[state, dispatch]}>{children}</Context.Provider>
);
}
const ButtonBar = () => {
const [polls] = useContext(Context);
const [state, setState] = useState(polls);
useEffect(() => {
setState(polls);
}, [polls]);
const filterResult = useMemo(() => {
return filter => {
switch (filter) {
case "SHOW_ALL":
setState(polls);
break;
case "SHOW_APPROVAL":
setState(polls.filter(e => e.type === "trump-approval"));
break;
default:
return;
}
};
}, [polls]);
return (
<div class="mb-2">
<button
class="btn btn-primary btn-sm"
name="all"
onClick={() => filterResult("SHOW_ALL")}
>
All
</button>{" "}
<button
class="btn btn-primary btn-sm"
name="trump approval"
onClick={() => filterResult("SHOW_APPROVAL")}
>
Trump Approval
</button>
<div>{(state || []).length}</div>
<pre>{JSON.stringify(state, null, 4)}</pre>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider>
<ButtonBar />
</Provider>,
rootElement
);
import-React{
使用效果,
使用上下文,
用户教育者,
使用备忘录,
使用状态
}从“反应”;
从“react dom”导入react dom;
导入“/styles.css”;
从“时刻”中导入时刻;
从“axios”导入axios;
export const Context=React.createContext();
常量url=”https://projects.fivethirtyeight.com/polls/polls.json";
导出常量filterReducer=(状态、操作)=>{
开关(动作类型){
案例“添加投票”:
console.log(action.payload);
返回动作。有效载荷;
违约:
返回州。民意测验;
}
};
导出函数提供程序({children}){
const[state,dispatch]=useReducer(filterReducer);
useffect(()=>{
var dateRange=力矩()
.减去(7,“天”)
.日历();
axios
.get(url)
。然后(res=>{
派遣({
键入:“添加投票”,
有效载荷:res.data
.filter(e=>Date.parse(e.endDate)>=Date.parse(dateRange))
.reverse()
});
}, [])
.catch(错误=>console.log(错误));
}, []);
返回(
{儿童}
);
}
常量按钮栏=()=>{
const[polls]=useContext(上下文);
const[state,setState]=使用状态(轮询);
useffect(()=>{
设置状态(投票);
},[民意测验];
const filterResult=useMemo(()=>{
返回筛选器=>{
开关(过滤器){
案例“全部展示”:
设置状态(投票);
打破
案例“显示批准”:
设置状态(polls.filter(e=>e.type==“特朗普批准”);
打破
违约:
返回;
}
};
},[民意测验];
返回(
filterResult(“全部显示”)}
>
全部的
{" "}
filterResult(“显示批准”)}
>
特朗普批准
{(状态| |[]).length}
{JSON.stringify(state,null,4)}
);
};
const rootElement=document.getElementById(“根”);
ReactDOM.render(
,
根元素
);
useState
hook不返回3个值。它只返回sta