React训练营:Advanced React Hooks:useContext与useReducer
概述
本文将介绍如何在React中使用Hook获取组件的数据,更进一步使用Redux进行跨组件的数据传递。配置环境后,你将了解如何编写Context、Reducer代码。
重要
- 本文将给出如下内容:
- React中组件之间的数据流向
- 跨组件数据传递 Context Reducer
- 在一个社交App的开发中,将主文件的数据传递给子组件 App->PostList->Post
- 数据直接从App传递到Post
前置条件
- 构建react项目
- react中构建组件
React Hooks
React Hooks 用于组件之间的数据传递,相当于用一个钩子把函数调用过程中的变量“钩”出来。
在React开发中,组件之间的数据传递需要学习的语法为Context和Reducer的方式进行数据传递。
useContext
useContxt顾名思义,为上下文,在计算机科学中,有Context Free Language 和 Non-Context Free Language。在React中其实就是一种上下文的数据传递形式,例如组件A->组件B的单向数据流动,那么根据常见的思路:也可以理解为生产者->消费者模式。
采用Context传递数据的案例:假设在一个社交系统中,App组件中记录了登录的用户信息,此时如果要将这个信息传递到用户消息的子组件中,并显示出来:
- 在App组件中定义全局的Context
export const UserContext = React.createContext();
App函数中定义状态:
const [user,setUser] = React.useState('mttt');
const [posts,setPosts] = React.useState([]);
使用UserContext,render的返回值为:
<UserContext.Provider value={user}>
<PostList posts={posts}></PostList>
</UserContext.Provider>
由于之前定义了[user,setUser]
作为状态,此时的<Provider/>
中value的值为user
,该组件将数据传递到子组件
- 在PostList组件中
import React from "react";
import Post from "./Post";
function PostList({posts}) {
return <div>
{posts.map((post,i)=>(<Post key={i}
image={post.image}
content={post.content}
user={post.user}/>))}
</div>;
}
export default PostList;
3.在Post 组件中使用父组件的Context:(注意该代码中有两种传递数据的方式)
1)Post()函数的参数,({image,content,user})
2)使用Context,在App函数中定义了UserContext.Provider
,需要使用参数的Post组件上,导入并使用useContext(UserContext)
。Post组件中,像钩子一样把数据从App这个组件中勾出来
import React from "react";
import {UserContext} from '../App';
function Post({image,content,user}){
const currentUser = React.useContext(UserContext);
const isCurrentUser = currentUser === user;
return (
<>
<div>
<p>{content}</p>
<div style={{color:isCurrentUser&&'green'}}>{user}</div>
</div>
{image && (
<img
style={{height:100, width:200, obejct:'cover'}}
src = {URL.createObjectURL(image)}
alt = "Post cover"
/>)}
</>
);
}
export default Post;
数据流向为:
App组件到PostList组件,在函数的参数中使用变量{posts}
进行参数传递,PostList组件到Post组件,也是使用类似的方法,就像钩子一样,把数据勾出来,但是此时通过函数参数单方向传递数据,只能一层一层传递参数,演示的例子中,使用了Context也就是最上层的App组件中定义了<UserContext.Provider value={user}>
,作为数据生产者,而在最底层的Post组件中使用了const currentUser = React.useContext(UserContext);
作为数据的消费者,得到了顶层组件的数据,此时的数据可以跨层流动,相比于直接通过函数参数的数据传递,Context的方式传递,自由度更大!
使用Reducer
Reducer使用纯函数的思想,参数为state和action,返回值为newState
state: state = {value: }
action:const action={type:"LOGIN_USER",payload:{ username:"xmmt"}};
const initialState = { user:""};
function userReducer(state=initialState,action){
switch(action.type){
case "LOGIN_USER": {
return {
...state,
user: action.payload.username };
}
case "LOGOUT_USER": {
...state,
user:""
}
default:
return state;
}
}
const loginAction = { type:"LOGIN_USER",payload:{username:"xmmt"}};
const logoutAction = { type:"LOGOUT_USER"}
userReducer(initialState,loginAction);
userReducer(initialState,logoutAction);
使用Reducer 对用户评论列表进行新增和删除
Reducer的定义,编写state 和 action
function postReducer(state,action){
switch (action.type) {
case "ADD_POST":{
const newPost = action.payload.post;
return { posts:[newPost,...state.posts]};
}
case "DELETE_POST":{
const deletePostId = action.payload.id;
return { posts:state.posts.filter(post=>post.id!==deletePostId)}
}
default:
return state;
}
}
export default postReducer;
App组件
全局变量posts存储用于发送的评论(微博)之类的内容:
export const PostContext = React.createContext({
posts:[]
});
function App(){
...
const [state,dispatch] = React.useReducer(postReducer,initialPostState);
return (
...
<PostList posts={state.posts}></PostList>
...
)
}
参数从App到PostList再到Post组件
import React from "react";
import {UserContext,PostContext} from '../App';
function Post({image,content,user,id}){
const { dispatch } = React.useContext(PostContext);
const currentUser = React.useContext(UserContext);
const isCurrentUser = currentUser === user;
function handleDeletePost(){
dispatch({type:"DELETE_POST",payload:{id:id}});
}
return (
<>
<div>
<p>{content}</p>
<div style={{color:isCurrentUser&&'green'}}>{user}</div>
</div>
{image && (
<img
style={{height:100, width:200, obejct:'cover'}}
src = {URL.createObjectURL(image)}
alt = "Post cover"
/>)}
{ isCurrentUser && <button onClick={handleDeletePost}>Delte</button>}
</>
);
}
export default Post;
数据流向