我在Profile
组件中有我的useEffect
,如下所示:
const [mappedPosts, setMappedPosts] = useState(null);
useEffect(() => {
fetchMedia();
if (userPosts) {
console.log("This keeps entering!");
const mapped = userPosts.map((post, index) => (
<View key={index}>
<Text>{post.title}</Text>
</View>
));
setMappedPosts(mapped);
}
}, []);
我的Profile
组件返回,
return mappedPosts ? (
<View>
{mappedPosts}
</View>
) : (
<Spinner />
);
我的问题如下:
当我有以下情况时,Spinner
组件将呈现:
useEffect(() => {
fetchMedia();
if (userPosts) {...};
setMappedPosts(mapped);
}
}, []);
或
useEffect(() => {
fetchMedia();
if (userPosts) {...};
setMappedPosts(mapped);
}
}, [mappedPosts]);
当我有以下情况时,将呈现适当的数据:
useEffect(() => {
fetchMedia();
if (userPosts) {...};
setMappedPosts(mapped);
}
}, [userPosts]);
或
useEffect(() => {
fetchMedia();
if (userPosts) {...};
setMappedPosts(mapped);
}
});
最后两个的问题是一遍又一遍地打印行console.log("This keeps entering!");
,表明组件不断重新渲染。我不确定我在这里做错了什么。下面的变体也会不断重新渲染组件:
const [mappedPosts, setMappedPosts] = useState(null);
useEffect(() => {
fetchMedia();
if (userPosts && mappedPosts === null) {
console.log("entered!");
const mapped = userPosts.map((post, index) => (
<View key={index}>
<Text>{post.title}</Text>
</View>
));
setMappedPosts(mapped);
}
}, [userPosts]);
console.log("am I being re-rendered?");
return mappedPosts ? (
<View>
{mappedPosts}
</View>
) : (
<Spinner />
);
我知道这一点,因为console.log("am I being re-rendered?");
不停地打印......即使数据已经呈现并在屏幕上适当地显示(我使用的是 react-native(。
Profile
组件从 redux 存储中获取userPosts
:
const Profile = ({
navigation,
posts: { userPosts, loading },
auth: { isAuthenticated },
fetchMedia,
checkAuth
}) => {
const [mappedPosts, setMappedPosts] = useState(null);
useEffect(() => {
fetchMedia();
.......
>编辑:fetchMedia
:
export const fetchMedia = () => async dispatch => {
dispatch({
type: FETCH_MEDIA
});
try {
const response = await axios.get(`http://${GATEWAY}:5000/api/posts/user`);
dispatch({
type: MEDIA_SUCCESS,
payload: response.data
});
} catch (err) {
dispatch({
type: MEDIA_FAIL
});
}
};
减速器:
const initialState = {
userPosts: null,
loading: false
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case FETCH_MEDIA:
return {
...state,
loading: true
};
case MEDIA_SUCCESS:
return {
...state,
userPosts: payload,
loading: false
};
case MEDIA_FAIL:
return {
...state,
loading: false
};
default:
return state;
}
}
所以我想通了。问题是每次组件更改时都会调用 fetchMedia。所以一旦userPosts
被取回..他们又被拿走了。再说一遍。再说一遍。这就是组件不断重新渲染的原因。这是我所做的更改:
useEffect(() => {
if (userPosts) {
console.log("entered!");
const mapped = userPosts.map((post, index) => (
<View key={index}>
<Text>{post.title}</Text>
</View>
));
setMappedPosts(mapped);
} else {
fetchMedia();
}
}, [userPosts]);
您的答案可能会起作用,因为数据只会被获取一次,并且userPost
永远不会更改引用。
通常,将 REST 数据置于状态中比您执行的操作要复杂一些。如果您需要数据,则容器将选择如下所示的数据:
const NOT_REQUESTED = {requested:false}
state => state.data.someData || NOT_REQUESTED
然后,如果未请求数据,组件可以请求数据。
useEffect(()=>requested || fetchData(),[requested])
化简器将设置请求和加载作为对请求操作的响应:
{
...state,
data: {
...state.data,
someData: { requested: true, loading: true },
},
};
现在,当您的组件将重新渲染但未调用fetchData
时,因为请求为 true。
当请求成功时,化简器可以在数据成功操作上写入结果:
{
...state,
data: {
...state.data,
someData: {
...state.data.someData,
loading: false,
data: action.data,
},
},
};
这不是服务器端过滤,排序,过时数据或错误处理,但我希望您能理解。
如果您希望组件调度操作来加载数据,那么您的容器/选择器需要生成指示是否已请求数据的 props。