问题
I am loading data from a public API after my component is mounted. When the data is loaded I am passing it to the reducer, but it always fires twice. This is what I have:
function MyComponent(props) {
function reducer(data, action) {
switch (action.type) {
case 'INITIALIZE':
return action.payload;
case 'ADD_NEW':
const newData = {...data};
newData.info.push({});
return newData;
}
}
const [data, dispatch] = React.useReducer(reducer, null);
useEffect(() => {
fetch(URL)
.then(response => {
dispatch({
type: 'INITIALIZE',
payload: response
});
})
.catch(error => {
console.log(error);
});
}, []);
const addNew = () => {
dispatch({ type: 'ADD_NEW' });
}
return(
<>data ? data.info.length : 'No Data Yet'</>
);
}
As you can see the component awaits for the data to populate the reducer, which, when INITIALIZE
is also called twice, but I didn't care about it until I needed to call ADD_NEW
, because in that case it adds two blank objects into the array instead of only one. I wen't into the documentation for side effects, but I was unable to solve it.
What is the best way to deal with this?
回答1:
Here's how I would deal with the issue. The main reason why it was re-running the action effect was because you had the reducer in the component's function. I also went ahead and fixed several other issues.
The fetch code was a little off due to how fetch works. You have to get the data type off of the response which gives another promise instead of the data directly.
You also needed to make the rendering use {} to indicate that you were using javascript rather than text.
import React, { useReducer, useState, useEffect } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import "./style.css";
const url = `https://picsum.photos/v2/list?page=3&limit=1`;
function App(props) {
const [data, dispatch] = React.useReducer(reducer, null);
useEffect(() => {
fetch(url)
.then(async response => {
dispatch({
type: "INITIALIZE",
payload: (await response.json())
});
})
.catch(error => {
console.log(error);
});
}, []);
const addNew = () => {
dispatch({ type: "ADD_NEW" });
};
console.log("here");
return (
<>
<div>{data ? JSON.stringify(data) : "No Data Yet"}</div>
<button onClick={addNew}>Test</button>
</>
);
}
render(<App />, document.getElementById("root"));
function reducer(data, action) {
switch (action.type) {
case "INITIALIZE":
console.log(action.payload, "Initialize");
return action.payload;
case "ADD_NEW":
const newData = { ...data };
newData.info = newData.info || [];
newData.info.push({});
console.log(newData);
return newData;
}
}
来源:https://stackoverflow.com/questions/61071171/react-hook-usereducer-always-running-twice